我想使用惯用的Perl 6进行此操作。
我在嘈杂的输出文件中发现了一个美妙的连续数据块。
我想简单地打印出以Cluster Unique
开头的标题行及其后的所有行,直到但不包括第一次出现的空行。这是文件的样子:
</path/to/projects/projectname/ParameterSweep/1000.1.7.dir> was used as the working directory.
....
Cluster Unique Sequences Reads RPM
1 31 3539 3539
2 25 2797 2797
3 17 1679 1679
4 21 1636 1636
5 14 1568 1568
6 13 1548 1548
7 7 1439 1439
Input file: "../../filename.count.fa"
...
这是我想解析的内容:
Cluster Unique Sequences Reads RPM
1 31 3539 3539
2 25 2797 2797
3 17 1679 1679
4 21 1636 1636
5 14 1568 1568
6 13 1548 1548
7 7 1439 1439
我想使用惯用的Perl 6进行此操作。
在Perl中,在文件中定位块的惯用方式是在段落模式中读取文件,然后在找到感兴趣的块时停止读取文件。读取10GB的文件,并且该块位于文件的顶部,那么继续读取文件的其余部分效率很低-更少地对文件的每一行执行if测试。
在Perl 6中,您可以像这样同时阅读一段内容:
my $fname = 'data.txt';
my $infile = open(
$fname,
nl => "\n\n", #Set what perl considers the end of a line.
); #Removed die() per Brad Gilbert's comment.
for $infile.lines() -> $para {
if $para ~~ /^ 'Cluster Unique'/ {
say $para.chomp;
last; #Quit reading the file.
}
}
$infile.close;
# ^ Match start of string.
# 'Cluster Unique' By default, whitespace is insignificant in a perl6 regex. Quotes are one way to make whitespace significant.
但是,在perl6 rakudo/moarVM
中,open()
函数无法正确读取nl
参数,因此您当前无法设置段落模式。
此外,有些习惯用法被某些人认为是不好的做法,例如:
Postif if语句,例如say 'hello' if $y == 0
。
依赖于代码中的隐式$_
变量,例如.say
因此,根据您所居住的篱笆的哪一侧,在Perl中将其视为bad做法。
.say if /Cluster \s+ Unique/ ff^ /^\s*$/ for lines;
打印输入文件中的每一行,从包含短语Cluster Unique
的那一行开始,直到下一个空行的结尾。
.say # print the default variable $_
if # do the previous action (.say) "if" the following term is true
/Cluster \s+ Unique/ # Match $_ if it contains "Cluster Unique"
ff^ # Flip-flop operator: true until preceding term becomes true
# false once the term after it becomes true
/^\s*$/ # Match $_ if it contains an empty line
for # Create a loop placing each element of the following list into $_
lines # Create a list of all of the lines in the file
; # End of statement
for lines() {
.say if (
$_ ~~ /Cluster \s+ Unique/ ff^ $_ ~~ /^\s*$/
)
}
lines()
类似于perl5中的<>
。一次列出一个命令行中列出的每个文件的每一行。因为这是在for
循环中,所以每一行都放在默认变量$_
中。say
类似于print,但它还会附加一个换行符。当以开头.
编写时,它直接作用于默认变量$_
。$_
是默认变量,在这种情况下,它包含文件中的一行。~~
是将$_
与正则表达式进行比较的匹配运算符。//
在两个正斜杠之间创建一个正则表达式\s+
匹配一个或多个空格ff
是flip-flop operator。只要左边的表达式为假,它就是假的。当其左侧的表达式被评估为true时,它将变为true。当右边的表达式变为真时,它将变为假,并且永远不会再次被评估为真。在这种情况下,如果我们使用^ff^
而不是ff^
,则标头将不包含在输出中。^
在ff
之前(或之后)时,它会修改ff
,因此,其左侧(或右侧)表达式变为true的迭代也为假。/^\*$/
匹配一个空行^
匹配字符串的开头\s*
匹配零个或多个空格$
匹配字符串的结尾顺便说一句,当在标量上下文中时,Perl 5中的触发器运算符为..
(在列表上下文中为范围运算符)。但是它的功能当然不如Perl 6丰富。