2

我想使用惯用的 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
4

2 回答 2

6

单线版

.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触发器运算符。只要它左边的表达式是假的,它就是假的。当其左侧的表达式被评估为真时,它变为真。当右边的表达式为真并且不再被评估为真时,它变为假。在这种情况下,如果我们使用^ff^而不是ff^,那么标题将不会包含在输出中。
  • ^出现在之前(或之后)ff时,它会修改ff它以使其左侧(或右侧)的表达式变为真的迭代也为假。
  • /^\*$/匹配一个空行
    • ^匹配字符串的开头
    • \s*匹配零个或多个空格
    • $匹配字符串的结尾

顺便说一句,Perl 5 中的触发器运算符..是在标量上下文中时(它是列表上下文中的范围运算符)。但它的特性当然不如 Perl 6 丰富。

于 2015-03-20T22:42:05.523 回答
3

我想使用惯用的 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正确读取参数,因此您目前无法设置段落模式。

此外,有些人认为某些习语是不好的做法,例如:

  1. 后缀 if 语句,例如say 'hello' if $y == 0.

  2. 依赖$_代码中的隐式变量,例如.say

所以,根据你住在哪一边,这在 Perl中会被认为是不好的做法。

于 2015-03-22T03:25:20.307 回答