虽然我认为这会创建一个格式奇怪的 CSV 文件,但使用 PowerShell,您可以将 switch 与 -Regex 和 -File 参数一起使用。这可能是处理大文件的最快方式,并且只需要几行代码:
# create a regex that will find comma's unless they are inside single quotes
$commaUnlessQuoted = ",(?=([^']*'[^']*')*[^']*$)"
$result = switch -Regex -File 'D:\test.csv' {
# added -replace "'" to also remove the single quotes as commented
default { $_ -replace "$commaUnlessQuoted", '|*' -replace "'" }
}
# output to console
$result
# output to new (sort-of) CSV file
$result | Set-Content -Path 'D:\testoutput.csv'
更新
作为mklement0 pointed out,上面的代码完成了这项工作,但代价是在写入输出文件之前完全在内存中将更新的数据创建为数组。
如果这是一个问题(文件太大而无法容纳可用内存),您还可以更改代码以读取/替换原始行并立即将该行写出到输出文件。
下一种方法几乎不会占用任何内存,但当然是以在磁盘上执行更多写入操作为代价的。
# make sure this is an absolute path for .NET
$outputFile = 'D:\output.csv'
$inputFile = 'D:\input.csv'
# create a regex that will find comma's unless they are inside single quotes
$commaUnlessQuoted = ",(?=([^']*'[^']*')*[^']*$)"
# create a StreamWriter object. Uses UTF8Encoding without BOM (Byte Order Mark) by default.
# if you need a different encoding for the output file, use for instance
# $writer = [System.IO.StreamWriter]::new($outputFile, $false, [System.Text.Encoding]::Unicode)
$writer = [System.IO.StreamWriter]::new($outputFile)
switch -Regex -File $inputFile {
default {
# added -replace "'" to also remove the single quotes as commented
$line = $_ -replace "$commaUnlessQuoted", '|*' -replace "'"
$writer.WriteLine($line)
# if you want, uncomment the next line to show on console
# $line
}
}
# remove the StreamWriter object from memory when done
$writer.Dispose()
结果:
123|*abc,def,ghf|*ajajaj|*1
345|*abdf|*abc,def,ghi|*2
556|*abdf|*def|*3
999|*a,b,d|*d,e,f|*4
正则表达式详细信息:
, Match the character “,” literally
(?= Assert that the regex below can be matched, starting at this position (positive lookahead)
( Match the regular expression below and capture its match into backreference number 1
[^'] Match any character that is NOT a “'”
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
' Match the character “'” literally
[^'] Match any character that is NOT a “'”
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
' Match the character “'” literally
)* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
[^'] Match any character that is NOT a “'”
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
$ Assert position at the end of the string (or before the line break at the end of the string, if any)
)