除非双引号内存在逗号,否则Powershell脚本将从CSV中删除双引号

时间:2015-05-14 20:44:19

标签: regex powershell csv

我有以下文件格式的.csv:

In: "bob","1234 Main St, New York, NY","cool guy"

我希望删除内部没有逗号的双引号:

Out: bob,"1234 Main St, New York, Ny",cool guy

有没有办法在Powershell中做到这一点?

我查了一下:

  1. How to remove double quotes on specific column from CSV file using Powershell script
  2. http://blogs.technet.com/b/heyscriptingguy/archive/2011/11/02/remove-unwanted-quotation-marks-from-csv-files-by-using-powershell.aspx
  3. https://social.technet.microsoft.com/Forums/windowsserver/en-US/f6b610b6-bfb2-4140-9529-e61ad30b8927/how-to-export-csv-without-doublequote?forum=winserverpowershell

4 个答案:

答案 0 :(得分:3)

调整"How to remove double quotes on specific column from CSV file using Powershell script"的代码:

$csv = 'C:\path\to\your.csv'
(Get-Content $csv) -replace '(?m)"([^,]*?)"(?=,|$)', '$1' |
    Set-Content $csv

正则表达式(?m)"([^,]*?)"(?=,|$)匹配任何" + 0 or more non-commas + " 之前逗号或行尾(通过正向前瞻和多行选项(?m)实现强制$匹配换行符,而不仅仅是字符串的结尾。

请参阅regex demo

答案 1 :(得分:1)

我不确切地知道你脚本的其余部分是什么样的。尝试沿着这些方向尝试

(("bob","1234 Main St, New York, NY","cool guy") -split '"' | 
  ForEach-Object {IF ($_ -match ",") {'"' + $_ + '"' } ELSE {$_}}) -join ","

答案 2 :(得分:1)

PowerShell [Core] v7 + 中,您现在可以将-UseQuotes AsNeededConvertTo-CsvExport-Csv一起使用,这大大简化了方法:

@'
Name,Address,Comment
"bob","1234 Main St, New York, NY","cool guy"
'@ | ConvertFrom-Csv | 
       ConvertTo-Csv -UseQuotes AsNeeded # use Export-Csv to save to a file.

上面的代码产生了以下内容,表明只有带有嵌入式,的字段才被双引号引起来:

Name,Address,Comment
bob,"1234 Main St, New York, NY",cool guy

请参见Export-Csv v7+ docs

  • -UseQuotes接受AsNeededAlwaysNewer

  • 另外,还有-QuoteFields,它接受​​列(属性)名称的数组 (应有选择地使用引号)。

答案 3 :(得分:0)

现有答案适用于样本输入:

  • Wiktor Stribiżew's helpful answer,使用正则表达式标识不包含,的双引号字段,首先将整个输入文件加载到内存中,这样就可以将输入文件替换为单个管道中的结果。
    虽然这很方便 - 并且比逐行处理更快 - 但需要注意的是,它可能不适用于大型输入文件。
  • markg's helpful answer,它通过"字符将行拆分为字段,是大型输入文件的替代方法,因为它使用管道逐个处理输入行。
    (因此,无法使用结果直接更新输入文件。)

如果我们 概括 OP要求处理嵌入式"字符 的字段,我们需要采用不同的方法:

以下字段必须保留其封闭的双引号:

  • (必要)带有嵌入,字符的双引号字段。例如,
    "1234 Main St, New York, NY"
  • (必要)带有嵌入式"字符的双引号字段,每个RFC 4180必须转义为"",即加倍;例如,
    "Nat ""King"" Cole"

注意:
- 我们处理可能包含嵌入式换行符的字段,因为这需要一种根本不同的方法,因为自包含的逐行处理是没有的更长的时间。
- Wiktor Stribiżew的提示,提出正则表达式以强制匹配双引号字段与任意数量的嵌入式双引号,转义为"""([^"]*(?:""[^"]*)*)"

# Create sample CSV file with double-quoted fields that contain
# just ',', just embedded double quotes ('""'), and both.
@'
bob,"1234 Main St, New York, NY","cool guy"
nat,"Nat ""King"" Cole Lane","cool singer"
nat2,"Nat ""King"" Cole Lane, NY","cool singer"
'@ | Set-Content ./test.csv

Get-Content ./test.csv | ForEach-Object {
  # Match all double-quoted fields on the line, and replace those that 
  # contain neither commas nor embedded double quotes with just their content,
  # i.e., with enclosing double quotes removed.
  ([regex] '"([^"]*(?:""[^"]*)*)"').Replace($_, { param($match)
    $fieldContent = $match.Groups[1]
    if ($fieldContent -match '[,"]') { $match } else { $fieldContent }
  })
}

这会产生:

bob,"1234 Main St, New York, NY",cool guy
nat,"Nat ""King"" Cole Lane",cool singer
nat2,"Nat ""King"" Cole Lane, NY",cool singer

更新输入文件

与markg的答案一样,由于逐行处理,您无法直接使用同一管道中的输出更新输入文件。
要在以后更新iput文件,请使用临时输出文件,然后用它替换输入文件(...代表上面的Get-Content管道,仅使用$csvFile代替./test.csv }):

$csvfile = 'c:\path\to\some.csv'
$tmpFile = $env:TEMP\tmp.$PID.csv
... | Set-Content $tmpFile
if ($?) { Move-Item -Force $tmpFile $csvFile }

请注意,Set-Content默认使用系统的单字节扩展ASCII字符编码(即使help topic falsely states ASCII)。

使用-Encoding参数可以指定不同的编码,但请注意,Out-File / >的默认值UTF-16LE会导致无法识别CSV文件例如,通过Excel正确使用。