首页 > 解决方案 > Powershell 正则表达式替换未转义的双引号,后跟换行符

问题描述

我正在处理一个大型 csv 文件,其中包含用双引号括起来的字段,其中的文本描述包含未转义的双引号,我需要用转义的双引号替换。我尝试使用以下正则表达式:(?<!^|",)("(?:$[^"])|"(?!,"|$))它能够找到未转义的引号,除非它们后跟换行符。感激地收到解决此问题的任何帮助。

我知道 csv 格式不正确,但不幸的是无法控制,因此我需要能够更正格式以进行进一步处理。

例子:

"Field 1","Field 2","Field 3 "with unescaped quote"
followed by line break","Field 4"

需要变成:

"Field 1","Field 2","Field 3 ""with unescaped quote""
followed by line break","Field 4"

我正在使用的 Powershell 脚本如下:

    [string]$path = 'C:\ ...'
    [string]$directory = [System.IO.Path]::GetDirectoryName($Path);
    [string]$strippedFileName = [System.IO.Path]::GetFileNameWithoutExtension($Path);
    [string]$extension = [System.IO.Path]::GetExtension($Path);
    [string]$newFileName = $strippedFileName + [DateTime]::Now.ToString("yyyyMMdd-HHmmss") + $extension;
    [string]$newFilePath = [System.IO.Path]::Combine($directory, $newFileName);

    $reader = New-Object 'System.IO.StreamReader'($path, $true);
    $regex = [regex] '(?<!^|",)("(?:$[^"])|"(?!,"|$))'
    $writer = [System.IO.StreamWriter] $newFilePath;  

    try{
        while (($line = $reader.ReadLine()) -ne $null ){
            $newline = $line -replace $regex, '""';
            $writer.WriteLine($newline);            
        }
    }
    finally{
        $reader.Close();
        $writer.Close();
    }

标签: regexpowershellcsv

解决方案


下一次,尝试构建一个最小的、可重现的示例(也为您自己),因为它可能有助于更好地理解问题。
一个常见的缺陷是标准 cmdletGet-Content读取行流 ( string[]),其中每行本身不包含任何换行符,但在输出到显示或文件。您可以通过使用-Raw参数来解决此问题,但这会将所有内容读入内存并可能使其比实际更复杂。
我怀疑您实际上想要查找不以双引号开头的行,这意味着前面的csv行可能被截断。这意味着,在这种情况下,您希望将前一行与一个额外的双引号连接起来,重新插入换行符并添加当前行:

Get-Content .\Input.csv | Foreach-Object { $Previous = $Null } {
    if ($_.StartsWith('"')) { 
        $Previous
        $Previous = $_
    } else {
        $Previous += '"' + [Environment]::NewLine + $_
    }
} { $Previous } | Set-Content .\Output.csv

推荐阅读