powershell - 如何在使用 powershell 脚本导入 CSV 后保留空格?
问题描述
我目前正在研究一个小型 PowerShell 脚本,该脚本应该将带有翻译的 CSV 文件拆分为相应语言的单个文件。为此,我使用Import-Csv
cmdlet 导入源文件,该文件具有以下格式:
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 文件格式。它指出,空格应被视为字段的一部分,而不应被忽略。应该意味着不是必须,所以很可能真的没有选择。
是否有可能保留空间而无需我自己解析整个文件?
解决方案
这是一个比替换 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
。
推荐阅读
- c# - 带有 signalR 的属性的别名
- html - 如果 Bulma 工具提示在 y 上滚动的 xa 父容器上溢出,如何使其可见
- apache-kafka-streams - RocksDB 的 Kafka Streams 内存分配问题
- javascript - 将数据保存到 LocalStorage,然后使用 android Java 检索它
- java - 在 JpaRepository 中刷新 saveAll
- svg - Safari SVG 蒙版渲染故障(剪辑路径)
- c++ - 正在调用基类虚拟方法,而不是子类的覆盖实现
- forms - getEditResponseUrl -> 某些行的空白表格
- python - 在 python 中创建后台任务并与之交互
- java - 将 json 反序列化为可选列表不会获得数组元素