首页 > 解决方案 > 如何在使用 powershell 脚本导入 CSV 后保留空格?

问题描述

我目前正在研究一个小型 PowerShell 脚本,该脚本应该将带有翻译的 CSV 文件拆分为相应语言的单个文件。为此,我使用Import-Csvcmdlet 导入源文件,该文件具有以下格式:

ResourceId;GermanTranslation;EnglishTranslation;Check
0;Deutscher Text;English text;OK
1;  mit Leerzeichen  ;  with spaces  ;OK

目标是获取格式中翻译的逐行表示ResourceId|EnglishTranslation|。为此,我构建了以下脚本:

Set-Variable SOURCE_FILE -Option Constant -Value ".\sourceFile.csv"
Set-Variable RESULT_FILE -Option Constant -Value ".\resultFile.csv"

foreach ($row in (Import-Csv -Path $SOURCE_FILE -Delimiter ";")) {
    Add-Content -Path $RESULT_FILE -Value ($row.RessourceId + "|" + $row.EnglishTranslation + "|")
}

基本上,一切都按预期工作,但是当我检查结果时,我注意到一些元素开始的空格不再出现在结果中:

0|English text|
1|with spaces  |

不幸的是,我在MS 文档中没有找到解决这个问题的参数,所以一开始我不确定。之后,我查看了RFC 4180,它或多或少准确地描述了 CSV 文件格式。它指出,空格被视为字段的一部分,而不应被忽略。应该意味着不是必须,所以很可能真的没有选择。

是否有可能保留空间而无需我自己解析整个文件?

标签: powershell

解决方案


这是一个比替换 CSV 文件中的字符更强大(并且可能更快)的解决方案。

它使用 Microsoft.VisualBasic 程序集中的 .NET TextFieldParser类。它有一个TrimWhiteSpace属性,当设置为 时$false,保留每个字段的任何前导和尾随空格,即使该字段未包含在双引号中。

我已经将 .NET 代码封装在一个名为Import-CustomCsv. TextFieldParser它支持通过各种参数的一些附加选项。

Function Import-CustomCsv {
   [CmdletBinding()]
   param (
      [Parameter(Mandatory, ValueFromPipeline)] [String] $Path,
      [String[]] $Delimiter = ',',
      [String[]] $CommentTokens = '#',
      [switch] $TrimWhiteSpace,
      [switch] $HasFieldsEnclosedInQuotes
   )

   # Load Visual Basic assembly if necessary. Seems to be required only for PS 5.
   if (-not ([System.Management.Automation.PSTypeName]'Microsoft.VisualBasic.FileIO.TextFieldParser').Type) {
      Add-Type -AssemblyName 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   }   

   # Create a CSV parser
   $csvParser = New-Object Microsoft.VisualBasic.FileIO.TextFieldParser $Path

   try {
      # Set CSV parser options
      $csvParser.SetDelimiters( $Delimiter )
      $csvParser.CommentTokens = $CommentTokens
      $csvParser.TrimWhiteSpace = $TrimWhiteSpace
      $csvParser.HasFieldsEnclosedInQuotes = $HasFieldsEnclosedInQuotes

      # Read the header
      $header = $csvParser.ReadFields()

      while( -not $csvParser.EndOfData ) {
         # Read current line fields, pointer moves to the next line.
         $fields = $csvParser.ReadFields()

         # Associate each field with its name from the header by storing it in an
         # ordered hashtable.
         $namedFields = [ordered]@{}
         for( $i = 0; $i -lt $header.Count; $i++ ) {
            $namedFields[ $header[ $i ] ] = $fields[ $i ]
         }

         # Finally convert fields to PSCustomObject and output (implicitly)
         [PSCustomObject] $namedFields
      }
   }
   finally {
      # Make sure to close the file even in case of an exception.
      $csvParser.Close()
   }
}

使用示例:解析 CSV,保留空格:

Import-CustomCsv test.csv -Delimiter ';'

输出:

ResourceId GermanTranslation   EnglishTranslation Check
---------- -----------------   ------------------ -----
0          Deutscher Text      English text       OK
1            mit Leerzeichen     with spaces      OK

用法示例:解析 CSV,修剪空白(如Import-Csv):

Import-CustomCsv test.csv -Delimiter ';' -TrimWhiteSpace

输出:

ResourceId GermanTranslation EnglishTranslation Check
---------- ----------------- ------------------ -----
0          Deutscher Text    English text       OK   
1          mit Leerzeichen   with spaces        OK   

笔记:

上述两个示例在输出中保留了包含字段的双引号(如果有)。要删除字段周围的双引号,请传递参数-HasFieldsEnclosedInQuotes


推荐阅读