perl 如何将区间列表转换为包含在这些区间中的数字列表?

tquggr8v  于 2022-11-15  发布在  Perl
关注(0)|答案(1)|浏览(131)

我有一个很大的文件,如下所示:

esup_255_3      transdecoder   7655    8192         
esup_6093_1     transdecoder   2732    2774        
esup_25727_1    transdecoder   1       60 
...

列3和4表示数字间隔。
我尝试修改此文件,以使区间内包含的数字列表在不同的列中列出(此处为第5列),如下所示:

esup_255_3      transdecoder    7655    8192    7655     
esup_255_3      transdecoder    7655    8192    7656
esup_255_3      transdecoder    7655    8192    7657 
esup_255_3      transdecoder    7655    8192     ...    
esup_255_3      transdecoder    7655    8192    8192    
esup_6093_1     transdecoder    2732    2774    2732     
esup_6093_1     transdecoder    2732    2774    2733     
esup_6093_1     transdecoder    2732    2774    ....     
esup_6093_1     transdecoder    2732    2774    2774     
... and so on...

我认为Perl可能会对此有所帮助,但我对它还很陌生,我只精通bash,在这里我似乎找不到正确的方法来获得我需要的东西。

jexiocij

jexiocij1#

像这样的东西?

perl -lne 'my ($line, $from, $to) = /^(.*\s(\d+)\s+(\d+)\s*)$/; print "$line\t$_" for $from..$to;'

当我在你的代码片段上运行它时,它会打印出641行:

esup_255_3      transdecoder   7655    8192             7655
esup_255_3      transdecoder   7655    8192             7656
esup_255_3      transdecoder   7655    8192             7657
[...]
esup_255_3      transdecoder   7655    8192             8190
esup_255_3      transdecoder   7655    8192             8191
esup_255_3      transdecoder   7655    8192             8192
esup_6093_1     transdecoder   2732    2774         2732
esup_6093_1     transdecoder   2732    2774         2733
[...]
esup_6093_1     transdecoder   2732    2774         2773
esup_6093_1     transdecoder   2732    2774         2774
esup_25727_1    transdecoder   1       60   1
esup_25727_1    transdecoder   1       60   2
[...]
esup_25727_1    transdecoder   1       60   59
esup_25727_1    transdecoder   1       60   60

下面是说明。让我们从选项开始:

perl -lne

-e(“execute”或“evaluate”)只是告诉Perl命令行上的下一个内容是要运行的代码,因此它不会在标准输入中查找代码。
-n告诉它自动地逐行迭代它的输入;就好像有一个while (<>) {... }循环包裹着实际的代码。在循环体中,当前行位于主题变量$_中。
-l告诉它从输入中去掉换行符,并自动为每个打印出的字符串添加一个换行符;这基本上消除了图片中的换行符并简化了逻辑。
因此,程序将逐行读取输入,并在每一行上运行作为-e的参数给出的代码。让我们看看这段代码,它以下面的语句开头:

my ($line, $from, $to) = /^(.*\s(\d+)\s+(\d+)\s*)$/;

正则表达式没有显式的字符串进行匹配,因此它自动匹配当前行所在的$_。(因为^在开头,$在结尾)。由于最外面的括号,实际的行值也会被捕获,因此它将是匹配返回的第一个项,其被分配给变量$line
行的第一部分可以是任何内容(因为.*匹配所有内容),所以我们真正关注的是字符串结束的方式,而不是开始的方式。(\s),它的作用是确保我们不会遗漏以下任何一个数字。(\d+),括号中捕获了它,因此该值也将由匹配返回;这是第二次捕获,因此它进入赋值中的第二个变量$from。在这些数字之后,我们查找更多的空格(至少需要一个空格字符,但允许任何数字),后面是另一个数字序列;第二组数字将再次被捕获并返回,因此它将在最后一个变量$to中结束。最后,我们允许在最后一组数字后面跟随任意数量的可选尾随空格。
因此,在阅读第一行$_ = "esup_255_3 transdecoder 7655 8192 "之后,match +赋值语句会将$line设置为整个字符串的副本,将$from设置为7655,将$to设置为8192
然后我们来看看输出。这一行:

print "$line\t$_" for $from .. $to;

这是撰写此循环的简短方式:

foreach $_  ($from .. $to) {
   print "$line\t$_";
}

这意味着它循环从$from$to的所有数字,重用$_作为循环控制变量(这就是为什么我们必须将当前行复制到$line中)。对于范围内的每个值,它打印出整个行的副本,后跟一个制表符和当前数字。

相关问题