例如; 我有一个长文件,其中包含:
Somestring anotherstring -xone xcont othertring -yone ycont againother \
-detail "detail Contents within quote" stuff morestuff ..
Somestring anotherstring -xone xcont othertring -yone ycont againother \
morestrings -detail detailCont morestrings etc.. ..
理想的出局:
-xone xcont
-ycont ycont
-detail "detail Contents withing quote"
使用csv文件是理想的:
xone yone detail
xcont ycont "detail Contents within quote"
获得所需输出的最佳方法是什么?我一直在尝试使用非常有限的sed命令。我是perl的新手,所以也没有走到那里..请解释建议的解决方案。 在此先感谢!
答案 0 :(得分:1)
此问题由两部分组成:
匹配部分非常简单,使用正则表达式。每个标记都是连字符 - 后跟一些单词字符。作为正则表达式模式:-\w+
。
值似乎是一个单词(我们可以匹配\w+
)或带引号的字符串。假设此字符串不能包含其分隔符,我们可以使用"[^"]+"
,其中[^"]
是一个否定的字符类,它匹配任何但双引号字符。
我们如何结合这个?通过交替和命名捕获:
# I'll answer with Perl
my $regex = qr/-(?<key>\w+) \s+ (?: (?<val>\w+) | "(?<val>[^"]+)" )/x;
之后,$+{key}
包含密钥,$+{val}
包含该标记的值。我们现在可以提取一行中的所有标签。鉴于输入
Somestring anotherstring -xone xcont othertring -yone ycont againother \-detail "detail Contents within quote" stuff morestuff ..
Somestring anotherstring -xone xcont othertring -yone ycont againother \morestrings -detail detailCont morestrings etc.. ..
代码
use strict; use warnings; use feature 'say';
my $regex = ...;
while (<>) {
while (/$regex/g) {
say qq($+{key}: "$+{val}");
}
}
我们得到输出
xone: "xcont"
yone: "ycont"
detail: "detail Contents within quote"
xone: "xcont"
yone: "ycont"
detail: "detailCont"
要以表格格式打印出来,我们必须以特定结构收集数据。我假设每个标签可以为每一行发生一次。然后我们可以使用哈希来定义从标签到其值的映射。我们在一个数组中收集这些哈希值,每行一个。我们还必须收集所有标题的名称,以防一行不包含所有标题。现在我们的代码更改为:
use strict; use warnings; use feature 'say';
my $regex = ...;
my %headers;
my @rows;
while (<>) {
my %tags;
while (/$regex/g) {
$tags{$+{key}} = $+{val};
}
push @rows, \%tags;
@headers{keys %tags} = (); # define the headers
}
现在我们如何打印数据?我们可以将它们转储为制表符分隔值:
my @headers = keys %headers;
say join "\t", map qq("$_"), @headers;
say join "\t", map qq("$_"), @$_{@headers} for @rows;
输出:
"yone" "detail" "xone"
"ycont" "detail Contents within quote" "xcont"
"ycont" "detailCont" "xcont"
哦,列的顺序是随机的。如果我们使用Text::CSV
模块,我们可以做得更好。然后:
use Text::CSV;
my @headers = keys %headers;
my $csv = Text::CSV->new({ eol => "\n" });
$csv->print(\*STDOUT, \@headers);
$csv->print(\*STDOUT, [@$_{@headers}]) for @rows;
我们得到了输出:
yone,xone,detail
ycont,xcont,"detail Contents within quote"
ycont,xcont,detailCont
列的顺序仍然是随机的,但这可以通过排序来修复。
您可以通读Text::CSV
documentation来发现许多可以调整输出的选项。
答案 1 :(得分:0)
这可能适合你(GNU sed):
sed -r '/-(xone|yone|detail)/!d;s//\n\1/;s/[^\n]*\n//;s/\S+\s+("[^"]*"|\S+)/&\n/;P;D' file
这会查找包含字符串-xone
,-yone
或-detail
的行,并仅打印它们以及"
或其他单词所包含的以下字词。