用于从CSV中删除双引号的Powershell脚本,除非双引号中存在逗号

ycl3bljg  于 2023-05-04  发布在  Shell
关注(0)|答案(4)|浏览(285)

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

gopyfrb31#

修改"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

ui7jx7zq

ui7jx7zq2#

在**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,它接受一个 * 列(属性)名称数组 *,应该(有选择地)对该数组应用引号。
pengsaosao

pengsaosao3#

更新:在PowerShell [Core] v7+中,可能有一个更简单的解决方案:参见this answer

现有的答案与示例输入配合良好:

  • Wiktor Stribiżew's helpful answer使用正则表达式标识不包含,的双引号字段,它首先将整个输入文件加载到内存中,这使得可以在单个管道中使用结果替换输入文件。

虽然这很方便,而且比逐行处理更快,但需要注意的是,它可能不是大型输入文件的选项。

  • markg's helpful answer(按"字符将行拆分为字段)是大型输入文件的替代方案,因为它使用管道逐个处理输入行。

(As因此,输入文件不能直接用结果更新。)
如果我们***推广 * OP的要求,也处理包含 * 嵌入"字符的字段。***,我们需要一种不同的方法:
然后,以下字段必须保留其封闭双引号:

  • (必要的)带有,字符的双引号字段。例如,

"1234 Main St, New York, NY"

  • (必要时)带有嵌入"字符的双引号字段,根据RFC 4180,必须将其转义为"",即 doubled;例如,

"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 topicfalsely states ASCII)。
使用-Encoding参数允许您指定不同的编码,但请注意,UTF-16 LE(Out-File/>的默认值)会导致CSV文件无法被Excel正确识别。

x7rlezfr

x7rlezfr4#

我不知道你剧本的其他部分是什么样子。尝试一些沿着这些线虽然

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

相关问题