sed:替换分隔记录中引用字段中的双引号

sed: Replacing a double quote in a quoted field within a delmited record

给定一个可选引用的管道分隔文件,其中包含以下记录:

"foo"|"bar"|123|"9" Nails"|"2" "blah"|"blah"|456|"Guns "N" Roses"|"7" "brik"|"brak"|789|""BB" King"|"0" "yin"|"yang"|789|"John "Cougar" Mellencamp"|"5"

我想替换任何不在定界符旁边的双引号。

我使用了下面的,它几乎可以工作。除了一个例外。

sed "s/\([^|]\)\"\([^|]\)/'/g" a.txt

输出如下所示:

"foo"|"bar"|123|"9' Nails"|"2" "blah"|"blah"|456|"Guns 'N" Roses"|"7" "brik"|"brak"|789|"'BB' King"|"0" "yin"|"yang"|789|"John 'Cougar' Mellencamp"|"5"

如果第二组引号像 Guns "N" Roses 中那样由单个字符分隔,则它不会捕获第二组引号。有谁知道这是为什么以及如何解决?与此同时,我只是将输出通过管道传输到第二个正则表达式来处理特殊情况。我宁愿一次完成此操作,因为某些文件可能很大。

提前致谢。

您可以在 sed 中使用两次替换:

sed -r "s/([^|])\"([^|])/'/g; s/([^|])\"([^|])/'/g" file
"foo"|"bar"|123|"9' Nails"|"2"
"blah"|"blah"|456|"Guns 'N' Roses"|"7"
"brik"|"brak"|789|"'BB' King"|"0"
"yin"|"yang"|789|"John 'Cougar' Mellencamp"|"5"

sed 实现了一个 "while" 循环:

sed ':a; s/\([^|]\)"\([^|]\)/'\''/g; ta' file

如果之前的 s/// 命令替换了某些内容,t 命令将循环到标签 a。这样会重复替换,直到找不到其他匹配项。

此外,perl 无需循环即可处理您的情况,这要归功于零宽度先行:

perl -pe 's/[^|]\K"(?!\||$)/'\''/g'

但是它不处理连续的双引号,所以循环:

perl -pe 's//'\''/g while /[^|]\K"(?!\||$)/' file

您可能喜欢使用 \x27 而不是笨拙的 '\'' 方法在单引号字符串中插入单引号。适用于 perl 和 GNU sed。