PowerShell Import-CSV в Export-CSV с преобразованием типов

Я получаю кучу файлов с разделителями табуляции и хочу преобразовать их в файлы с разделителями-запятыми. Мне также нужны только два столбца из файла "Дата" и "Значение1", поэтому я отбрасываю остальные столбцы.

Date    Value1  Value2  Value3  Value4  Sensor
08.07.2010  115,28  115,45  115,45  115,28  100
07.07.2010  115,34  115,32  115,34  115,25  85
06.07.2010  115,23  115,74  115,74  115,20  203

Это работает следующим образом:

(get-ChildItem -Path '*.txt').name | ForEach-Object { 
    Import-Csv -Path $_ -Delimiter "`t" | 
    Select-Object -Property Date,Value1 | 
    Export-Csv "out\$_" 
}

К сожалению, в исходном файле запятая используется в качестве десятичного разделителя. Таким образом, я получаю эти файлы, где Value1 интерпретируется как строка:

"Date","Value1"
"24.02.2017","30,18"
"23.02.2017","30,20"
"22.02.2017","30,18"
"21.02.2017","30,18"
"20.02.2017","30,17"

Как я могу установить тип данных столбца числовой? В течение Import-CSV?

2 ответа

Export-CSV всегда добавляя "..." вокруг значений выходного поля нет (само по себе) проблемы:

  • Формат данных CSV не имеет внутренней концепции типа данных, и двойные кавычки используются исключительно для включения значения поля (что является синтаксическим требованием для значений поля со встроенным , chars., например).

  • Например, Excel выводит тип данных столбца исключительно из его содержимого, независимо от того, заключено ли это содержимое в двойные кавычки или нет.

    • Интерпретация контента, однако, учитывает культуру (локаль).
  • В отличие от PowerShell Import-Csv никогда не интерпретирует данные и возвращает все значения полей как строки.

В зависимости от активной культуры в среде, в которой будет обрабатываться CSV, у вас есть два варианта:

  • Для такой культуры, как de-DE (Германия), в которой , (запятая), а не . (точка, точка) используется в качестве десятичного знака, и ; скорее, чем , используется в качестве разделителя списка:

    • При действующей целевой культуре (проверьте с помощью Get-Culture) использовать Export-Csv -UseCulture
      (-UseCulture доступно начиная с (как минимум) v2 [1]). Спасибо, LotPings
    • В качестве альтернативы используйте что-то вроде Export-Csv -Delimiter ([cultureinfo]::GetCultureInfo('de-DE').TextInfo.ListSeparator)
  • Для англоязычной культуры (или любой другой культуры, которая использует . как десятичная дробь):

    • Произведите пользовательскую обработку файла и замените , экземпляры в числовых полях с . - увидеть ниже.

Чтобы заменить , случаи с ., следующая команда, которая использует только строковые манипуляции, сделает:

Get-ChildItem -Path *.txt | ForEach-Object {
  Get-Content -LiteralPath $_.FullName | ForEach-Object {
    ($_ -split '\t')[0,1] -replace ',', '.' -join ','
  } |
    Set-Content -Encoding utf8 "out/$($_.Name)"
}

Примечание. Для простоты команда предполагает, что Date значения столбца не содержат экземпляров , и что ни одно из значений не требует "..." - Включение - что является разумным в этом конкретном сценарии.

  • Я выбрал UTF-8 в качестве выходной кодировки выше, потому что Set-Content по умолчанию используется устаревшая, специфичная для культуры кодовая страница "ANSI" - при необходимости измените.

[1] Как правило, если в описании параметра в разделе справки по командлету не упоминается конкретная версия, в которой он был представлен, это означает, что он существует со времен v2. Теперь вы можете просматривать более старые версии документации - вплоть до версии 3 - на GitHub - просто введите T или нажмите Find file и начните вводить имя командлета / концептуального раздела справки.

Export-CSV добавляет кавычки независимо от типа. Вероятно, единственный способ сделать это - снова загрузить файл и использовать регулярные выражения для удаления этих кавычек:

(get-ChildItem -Path '*.txt').name | ForEach-Object { 
    Import-Csv -Path $_ -Delimiter "`t" | 
    Select-Object -Property Date,Value1 | 
    Export-Csv "out\$_" 
    (Get-Content $_) -replace ',"(\d+),(\d+)"$', ',$1.$2'  | Set-Content "out\$_"
}

Примечание: вы можете установить -Encoding для Set-Content командлета!

Другие вопросы по тегам