perl 如何找到所有不带双引号的换行符?

f8rj6qna  于 2022-11-15  发布在  Perl
关注(0)|答案(3)|浏览(194)

我想删除CSV文件中双引号之间的所有非法换行符LF。

"name", "created"
"David A","2022-04-04"
"Mark
B", "2022-04-09"
"Peter C", "2022-05-01"

例如,文件名为name.csv
现在我可以用

cat name.csv |
| perl -p -e 's/\n/!LF_SYMBOL!/g'        \
| perl -p -e 's/"!LF_SYMBOL!"/"!EOL!"/g' \
| perl -p -e 's/!LF_SYMBOL!//g'          \
| perl -p -e 's/!EOL!/\n/g'              \
> name_new.csv

我想删除所有不跟在双引号后面的换行符
我试过了

perl -p -e 's/[^"]\n//' name.csv

perl -p -e 's/^[^"]\n//' name.csv

两者都只是出于某种原因删除所有"\n
有什么想法吗?

6gpjuf90

6gpjuf901#

通常最好使用现有的解析器,而不是自己编写解析器,这也不例外。
Text::CSV_XS在处理双引号字段中的换行符时没有问题。[1]
如果提供了allow_whitespace => 1,它甚至可以容忍逗号后面的空格。
所以我会使用这个模块,而不是编写自己的解析器。
你所需要的就是:

perl -MText::CSV_XS=csv -e'
   csv
      in => *ARGV,
      allow_whitespace => 1,
      on_in => sub { s/\n//g for @{ $_[1] }; };
' name.csv >name_new.csv

输出量:

name,created
"David A",2022-04-04
MarkB,2022-04-09
"Peter C",2022-05-01

如果出于某种原因您不想使用XS,那么速度较慢的Text::CSV就是一个替代品。
1.处理字段中的换行符需要传递binary => 1,这是使用csv函数时的默认值。

ukxgm1gy

ukxgm1gy2#

如果这是一个有效的CSV文件,可以使用Text::CSV之类的库来读取它。它们不存在嵌入到字段中的换行符的问题,然后很容易删除这些换行符

use warnings;
use strict;
use feature 'say';

use Text::CSV;

my $file = shift or die "Usage: $0 file.csv\n";

my $csv = Text::CSV->new(
    { binary => 1, auto_diag => 1, allow_whitespace => 1 }); 

open my $fh, '<', $file  or die "Can't open $file: $!";

while (my $row = $csv->getline($fh)) { 
    s/\n+//g for @$row; 
    $csv->say(\*STDOUT, $row);
}

这也可以在一行程序中完成,如果这样做有一些好处的话。
发布的文本,因为它的立场,是不是有效的CSV和不能直接解析的图书馆,因为逗号之间的字段丢失。我认为这是打字错误,因为问题说“CSV”在多个地方。请澄清。
binary属性接受嵌入的换行符,而allow_whitespace属性接受逗号后面的额外空格(严格无效)。

bttbmeg0

bttbmeg03#

由于您有一个类似“CSV”的两列文件,而您所需要的只是删除两个字段中的换行符,因此可以使用如下解决方案

perl -0777 -i -pe 's/^("[^"]*(?:""[^"]*)*")\s*,\s*(?1)$/$&=~s!\R+!!gr/gme' file.csv

参见main regex demo。当找到匹配时,第二个正则表达式s!\R+!!gr删除匹配中的所有换行符。

  • 详细数据 *:
  • ^-行的开始(由于m标志)
  • ("[^"]*(?:""[^"]*)*")-组1:",零个或多个除"以外的字符,零个或多个""重复,零个或多个除"以外的字符,然后是"(匹配文字双引号用"转义的CSV字段)
  • \s*,\s*-以零个或多个空格括起的逗号
  • (?1)-重复组1模式的子程序
  • $-行尾(由于m标志)。

相关问题