首页 > 解决方案 > 如果数据中不存在分隔符值,则删除双引号

问题描述

给出了一个输入文件,其中的每一行都包含每列的引号和回车符/换行符。

举例来说,给定以下输入文件

"name","address","age"^M
"ram","abcd,^M
def","10"^M
"abhi","xyz","25"^M
"ad","ram,John","35"^M

我想通过 sed/perl/awk 脚本/oneliner 获得以下输出。

name,address,age
ram,"abcd,def",10
abhi,xyz,25
ad,"ram,John",35

到目前为止我已经厌倦的解决方案用于附加上一行

sed '/^[^"]*"[^"]*$/{N;s/\n//}' sample.txt

用于替换 control-m 字符

perl -pne 's/\\r//g' sample.txt

但我没有达到我下面要求的最终输出

标签: csvperlawksed

解决方案


使用库来解析 CSV 文件。除了总是想在这里使用库之外,您还有非常具体的原因,嵌入式换行符和分隔符。

在 Perl 中,一个好的库是Text::CSVText::CSV_XS (如果安装了它会包装)。一个基本的例子

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 }); 

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);
}

评论

  • 构造函数中的binary选项是处理嵌入数据的换行符

  • 将一行读入数组引用$row后,我会使用简单的正则表达式删除每个字段中的换行符。无论如何,如果需要,请改进它

  • 作品的修剪$row如下。在foreach循环中,每个元素都由循环变量起别名,因此如果更改,数组也会更改。我使用 default where elements are aliased by $_,正则表达式更改因此$row更改。

    我喜欢这个紧凑的快捷方式,因为它的外观非常独特,我可以从房间的另一头看出一个数组正在就地更改,因此可以将其视为一种惯用语。但如果它实际上令人困惑,请务必写出一个完整且正确的循环

  • 处理后的输出打印到STDOUT. 或者,打开一个输出文件并将该文件句柄传递给say(或print在较旧的模块版本中),以便输出直接到该文件

以上打印,用于问题中提供的示例输入

姓名、地址、年龄
内存,“abcd,def”,10
abhi,xyz,25
广告,“拉姆,约翰”,35

推荐阅读