【问题标题】:Having multiple double quotes inside quoted string csv file在带引号的字符串 csv 文件中有多个双引号
【发布时间】:2021-05-11 17:43:12
【问题描述】:

我有一个 csv 文件,每个字段都有引号。

有些字段里面可以有多个双引号。我想用额外的双引号来转义它们。

","ABC "XYZ" PQRS","
","ABC "XYZ"","
","ABC "A" "B" 测试","
","ABC 2.5" "C" 测试","

我得到了link 的帮助,并且能够使用正则表达式[regex]$r='(","[^"]+"[^"]+?",")' 覆盖内容内包含单双引号的场景。但是,在内容中有多个双引号的情况下会卡住。

[regex]$r='(","[^"]+"[^"]+"",")' # Not working
get-content C:\Projects\MyProject\testRegexFordoublequotes.csv | foreach {

  #save each line to a variable to make it easier to track

  $line=$_

  #look for a regex match

  $find=$r.matches($line)
  
  if ($find[0].Success) { 

      foreach ($match in $find) {

        #the original string we matched on

        $found=$match.value

        #replace the substring

        $replace= '","'+  $found.Trim('","').Replace('""','"').Replace('"','""')+ '","'

        #replace the full string and write to the pipeline

        $line -replace $found,$replace

      } #foreach
       

  } #if

  else {

        #no match so write the line to pipeline

        $line

    }

 } | Set-Content C:\Projects\MyProject\modified.csv -Force

您能否帮我定义正则表达式,这将有助于字段内的多个双引号。

【问题讨论】:

  • 使用Import-Csv之类的东西,而不是尝试自己解析。
  • @MattClark,感谢您的建议。由于某些字段的内容内包含双引号,导入失败。此外,大约有 25 万个这样的文件,并且有很多这样的字段。所以,想用正则表达式来做它更快
  • @MattClark,我不太擅长正则表达式。实现起来看起来很复杂。正如您的建议,让我看看是否可以使用 csv 解析器处理它。但是,我需要找出具有这些类型内容的文件
  • 正如其他人指出的那样,最好使用 CSV 解析器,例如 github.com/peterthoeny/parse-csv-js。但是,您的文本不符合 CSV,因此 CSV 解析器无济于事。这些是实际的线条还是缩短的线条?开头和结尾的"," 看起来很奇怪。此外,是否所有字段都用引号括起来,例如相邻字段是否总是由","分隔?

标签: regex powershell csv str-replace double-quotes


【解决方案1】:

搜索 有效 分隔符(例如 "\s*,\s*")并将行拆分为字段可能更容易,而不是简单地更正每个(无效)单双引号,每个字段中有 2 个引号.
通过用双引号将字段括起来并将它们与csv(逗号)分隔符连接起来,将字段重建为记录

输入

$Csv = @'
"Field","ABC "XYZ" PQRS","Field"
"Field","ABC "XYZ"","Field"
"Field","ABC "A" "B" TEST","Field"
"Field","ABC 2.5" "C" Test","Field"
'@ -Split '[\r\n]+'

脚本

$Csv | # replace with: get-content .\testRegexFordoublequotes.csv |
Foreach-Object {
    $Line = $_ -Replace '^\s*"' -Replace '"\s*$' # Strip outer double quotes
    $Fields = $Line -Split '"\s*,\s*"'           # Split line into fields
    $Fields = $Fields -Replace '"', '""'         # Escape each " in each field
    '"' + ($Fields -Join '","') + '"'            # Rejoin the fields to line
} # append: | Set-Content .\modified.csv -Force

输出

"Field","ABC ""XYZ"" PQRS","Field"
"Field","ABC ""XYZ""","Field"
"Field","ABC ""A"" ""B"" TEST","Field"
"Field","ABC 2.5"" ""C"" Test","Field"

【讨论】:

【解决方案2】:

根据我们在帖子 cmets 中的对话,这些文件是不符合标准的 CSV 文件,因此 CSV 解析器没有帮助。

请注意,如果单个单元格恰好有 some textext","more text,则您的情况未定义。由于未转义的引号,该单元格将被视为两个单元格。

现在到正则表达式。你可以找到一个带有lookahead和lookbehind的正则表达式,但我认为将所有引号加倍更容易,然后清理不想要的引号,例如在行首和行尾,以及单元格之间。

我不熟悉 powershell,但这里有一段 JavaScript/伪代码,您可以轻松地将其转换为 powershell 语法。我正在使用包含您声明的所有测试用例的单行;您将遍历文件中的行:

/* assume $line is:
"Start","ABC "XYZ" PQRS","ABC "XYZ"","ABC "A" "B" TEST","ABC 2.5" "C" Test","End"
*/

$fixed = $line.replace(/"/g, '""')
              .replace(/"",""/g, '","')
              .replace(/^""/, '"')
              .replace(/""$/, '"')

/* $fixed is:
"Start","ABC ""XYZ"" PQRS","ABC ""XYZ""","ABC ""A"" ""B"" TEST","ABC 2.5"" ""C"" Test","End"
*/

解释:

  • .replace(/"/g, '""') - 盲目地将所有引号加倍
  • .replace(/"",""/g, '","') - 恢复 "","" 回到 ","
  • .replace(/^""/, '"') - 将行首的 "" 恢复为 "
  • .replace(/""$/, '"') - 将行尾的 "" 恢复为 "

【讨论】:

  • 谢谢。解决问题的不同方法。很有用。我选择了另一个,考虑到将来有人在 power shell 语法中引用它很有用。感谢您的帮助。
【解决方案3】:

您可以执行以下操作以查看更改内容:

(Get-Content file.csv) -replace '(?<!^|",)"(?!,"|$)','""'

您可以简单地通过管道发送到Set-Content 以保存新内容:

(Get-Content file.csv) -replace '(?<!^|",)"(?!,"|$)','""' |
    Set-Content file.csv

说明:

(?&lt;!^|",) 是对不是行首 (^) 或 ", 的任何先前位置的负向后查找。 (?!,"|$) 是对不是行尾 ($) 或 ," 的任何下一个位置的负前瞻。如果满足这些环视条件," 将替换为 ""

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 2016-06-08
    • 1970-01-01
    • 2017-08-21
    • 2015-09-16
    • 2015-10-29
    • 1970-01-01
    相关资源
    最近更新 更多