在带引号的字符串csv文件中有多个双引号

问题描述

我有一个 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

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

解决方法

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

输入

$Csv = @'
"Field","ABC "XYZ" PQRS","Field"
"Field","ABC "XYZ"","ABC "A" "B" TEST","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","ABC ""XYZ""","ABC ""A"" ""B"" TEST","ABC 2.5"" ""C"" Test","Field"
,

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

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

现在到正则表达式。你可以找到一个带有前瞻和后视的正则表达式,但我认为盲目地将所有引号加倍,然后清理意外的引号更容易,例如在行首和行尾,以及单元格之间。

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

/* assume $line is:
"Start","End"
*/

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

/* $fixed is:
"Start","End"
*/

说明:

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

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

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

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

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

说明:

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...