arrays - 解析带有引用字段的字符串,如 Powershell 中的 CSV 行

标签 arrays powershell csv

我必须将变量输入字符串解析为字符串数组。
输入是 CSV 样式的逗号分隔字段列表,其中每个字段都有自己的带引号的字符串。
因为我不想编写自己的成熟的 CSV 解析器,所以到目前为止我可以创建的唯一可行的解​​决方案是:

$input = '"Miller, Steve", "Zappa, Frank", "Johnson, Earvin ""Magic"""'

Add-Type -AssemblyName Microsoft.VisualBasic
$enc = [System.Text.Encoding]::UTF8
$bytes = $enc.GetBytes($input)
$stream = [System.IO.MemoryStream]::new($bytes)
$parser = [Microsoft.VisualBasic.FileIO.TextFieldParser]::new($stream)
$parser.Delimiters = ','
$parser.HasFieldsEnclosedInQuotes = $true
$list = $parser.ReadFields()

$list
输出如下所示:
Miller, Steve
Zappa, Frank
Johnson, Earvin "Magic"
Powersell 的另一个 .NET 库是否有更好的解决方案?
在最好的情况下,我可以避免这种额外的字节数组和流。
我也不确定这个 VisualBasic-Assembly 是否能长期使用。
这里有什么想法吗?

最佳答案

通过一些额外的安全预防措施并防止意外的字符串外推,您可以结合使用 Invoke-Expression Write-Output ,但请注意 Invoke-Expression should generally be avoided :

$fieldList = '"Miller, Steve", "Zappa, Frank", "Johnson, Earvin ""Magic""", "Honey, I''m $HOME"'

# Parse into array.
$fields = (
  Invoke-Expression ("Write-Output " + ($fieldList -replace '\$', "`0"))
) -replace "`0", '$$'
笔记:
  • -replace '\$', "`0"暂时替换文字 $字符。在带有 NUL 字符的输入中。防止意外(或恶意)string expansion (interpolation) ;第二个 -replace操作恢复原状$字符。
    this answer有关基于正则表达式的更多信息 -replace运算符(operator)。
  • 如果仅当输入字符串保证从不包含嵌入的 $ 时字符 ,解决办法可以是简化版 到:
    $fields = Invoke-Expression "Write-Output $fieldList" 
    

  • 输出 $fields产生以下结果:
    Miller, Steve
    Zappa, Frank
    Johnson, Earvin "Magic"
    Honey, I'm $HOME
    

    约束说明和列表 :
    该解决方案依赖于将输入字符串作为内容在语法上有效的字符串的一部分 Write-Output调用,输入字符串作为后者的参数。 Invoke-Expression然后评估这个字符串,就好像它的内容已经作为命令直接提交一样,因此执行 Write-Output命令。根据 PowerShell 解析命令参数的方式,这意味着以下约束:
  • 支持的字段分隔符:
  • 要么: , -分隔 (每个字段(未加引号)前导和/或尾随空格被删除,如上所示)。
  • 或:空格分隔 , 在字段之间使用一个或多个空白字符。

  • 嵌入字段的非/引用 :
  • 可以引用字段:
  • 单引号 ( '...' ), 字段内部 '字符必须转义为 '' .
  • 双引号 , 现场-内部 "字符必须转义为 ""`" .

  • 字段也可以不加引号:
  • 但是,此类字段不得包含任何 PowerShell 参数模式元字符(其中,< > @ # 只是标记开头的元字符):
     <space> ' " ` , ; ( ) { } | & < > @ #        
    



  • 替代方法,通过 ConvertFrom-Csv :
    iRon's helpful answer显示了基于 ConvertFrom-Csv 的解决方案,假设输入字符串中嵌入的字段列表是逗号分隔的 ( , ):
  • 一方面比较局限,只支持"..." -引用字段和 "" - 字段内部的转义" , 并且不支持由不同数量的空格分隔的字段(仅)。
  • 另一方面,它更灵活,因为它支持字段之间的任何单字符分隔符(不管每个字段的前导/尾随空格),这可以通过 -Delimiter 指定。范围。

  • 使解决方案尴尬的是需要预测最大值。嵌入字段的数量并为它们提供虚拟标题(列名)( -Header (0..99) ),以便使 ConvertFrom-Csv工作,这既脆弱又可能浪费。
    然而,一个简单的技巧可以绕过这个问题:提交输入字符串两次,在这种情况下 ConvertFrom-Csv将输入字符串中的字段视为列名和唯一一个输出行(对象)的列值,然后可以查询其值:
    $fieldList = '"Miller, Steve", "Zappa, Frank", "Johnson, Earvin ""Magic""", "Honey, I''m $HOME"'
    
    # Creates the same array as the solution at the top.
    $fields = ($fieldList, $fieldList | ConvertFrom-Csv).psobject.Properties.Value
    

    关于arrays - 解析带有引用字段的字符串,如 Powershell 中的 CSV 行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67422853/

    相关文章:

    c++ - ostream& 不命名类型错误。我在这里做错了什么?

    javascript - 在对数组执行 "double iteration"的同时对每个项目执行异步操作

    用于在 AD 中查询特定 OU 的计算机名称并导出的 Powershell 脚本

    powershell - 为什么Powershell将简单的整数运算转换为两倍?

    python - 使用 python 将数据文件从源工作表转换为目标工作表格式。

    javascript - 如何在唯一键内获取Firebase数据库嵌套数据访问

    C++ : array of coordinates?

    email - powershell send-mailmessage错误-helo命令被拒绝:需要标准主机名

    Python 将字典列表写入 csv

    powershell - Powershell追加CSV失败