我尝试使用Perl从输入文本文件格式转换为显示的输出文本文件格式,但不成功。
有人可以帮忙吗?
输入:
row1 multiline 1
row1 multiline 2
row1 multiline 3
row2 multiline 1
row2 multiline 2
预期产出:
row1 multiline 1 multiline 2 multiline 3
row2 multiline 1 multiline 2
答案 0 :(得分:3)
这会按照你的要求行事。它检查每行的第一个字段是否已更改,以决定是继续输出当前行还是开始新行
它希望输入文件的路径作为命令行上的参数
use strict;
use warnings;
my $row;
while ( <> ) {
next unless /\S/;
chomp;
my ( $new_row, $rest ) = split ' ', $_, 2;
if ( defined $row and $row eq $new_row ) {
print ' ', $rest;
}
else {
print "\n" if defined $row;
print $_;
$row = $new_row;
}
}
print "\n";
row1 multiline 1 multiline 2 multiline 3
row2 multiline 1 multiline 2
答案 1 :(得分:1)
在一个正则表达式?不太可能。然而,多次使用相同的正则表达式是合理的。只需匹配,直到它停止匹配:
while ($input =~ s/row(\d+)((?: multiline \d+)+)\n+row\1/row$1$2/gm){}
循环将在每次迭代时将未合并线的数量减少一半。因此它只会循环O(ln(n))
次。
您可以在此处看到它:https://ideone.com/RP30h6
<小时/> 上述解决方案更加深奥而实用。以下是真实解决方案的外观:
my $row_number = 0;
my ($row, $column);
while ($input =~ /(row(\d+) multiline (\d+))/gm) {
if ($row_number != $2) {
$row_number = $2;
} else {
$row = $1;
$column = $3;
$input =~ s/\n+$row/ multiline $column/g;
}
}
答案 2 :(得分:1)
这可以使用替换回调来完成
在Perl中,通常使用s///e
评估表单来完成。
这只是获取捕获缓冲区中的公共行块 缓冲区1是第一行,缓冲区3是剩余的公共行。
这些传递给合并子 合并子通过另一个正则表达式修剪公共行 然后将第一行与公共行组合起来 然后它作为替代品被传回。
Perl代码:
use strict;
use warnings;
$/ = undef;
my $input = <DATA>;
sub mergeRows {
my ($first_row, $other_rows) = @_;
$other_rows =~ s/(?m)\s*^\w+\s*(.*)(?<!\s)\s*/$1 /g;
return $first_row . " " . $other_rows . "\n";
}
$input =~ s/(?m)(^(\w+).*)(?<!\s)\s+((?:\s*^\2.*)+)/ mergeRows($1,$3) /eg;
print $input, "\n";
__DATA__
row1 multiline 1
row1 multiline 2
row1 multiline 3
row2 multiline 1
row2 multiline 2
输出:
row1 multiline 1 multiline 2 multiline 3
row2 multiline 1 multiline 2
主要正则表达式:
(?m) # Multi-line mode
( # (1 start), First of common row
^
( \w+ ) # (2), common row label
.*
) # (1 end)
(?<! \s ) # Force trim of trailing spaces
\s+ # Consume a newline, also get all the next whitespaces
( # (3 start), Remaining common row's
(?:
\s* ^ \2 .*
)+
) # (3 end)
合并子正则表达式:
(?m) # Multi-line mode
\s* # remove
^ \w+ \s* # remove
( .* ) # (1), What will be saved
(?<! \s ) # remove, force trim of trailing spaces
\s* # remove, possibly many newlines (whitespace)
答案 3 :(得分:1)
您有一个关键字段作为第一个单词,然后该行的其余部分作为值。
所以我会像这样处理你的问题:
#!/usr/bin/env perl
use strict;
use warnings;
my %rows;
while (<DATA>) {
my ( $key, $rest_of_line ) = (m/^(\w+) (.*)/);
push( @{ $rows{$key} }, $rest_of_line );
}
foreach my $key ( sort keys %rows ) {
print "$key ", join( " ", @{ $rows{$key} } ), "\n";
}
__DATA__
row1 multiline 1
row1 multiline 2
row1 multiline 3
row2 multiline 1
row2 multiline 2
与其他人的方法略有不同,因为我们将每行读入哈希值,然后输出哈希值。
它不会维护原始文件的顺序,而是按“行”值排序&#39;顺序。