0

我有一个看起来像这样的文件:

uniprotkb:Q9VNB0|intact:EBI-102551   uniprotkb:A1ZBG6|intact:EBI-195768
uniprotkb:P91682|intact:EBI-142245   uniprotkb:Q24117|intact:EBI-156442
uniprotkb:P92177-3|intact:EBI-204491     uniprotkb:Q9VDK2|intact:EBI-87444

我希望提取:|分隔符之间的字符串,输出应该是:

Q9VNB0   A1ZBG6
P91682   Q24117
P92177-3 Q9VDK2

制表符分隔在两列之间。我在 unix 中写了一个 perl 命令:

perl -l -ne '/:([^|]*)?[^:]*:([^|]*)/ and print($1,"\t",$2)' <file>

我得到的输出是:

Q9VNB0  EBI-102551   uniprotkb:A1ZBG6
P91682  EBI-142245   uniprotkb:Q24117
P92177-3    EBI-204491   uniprotkb:Q9VDK2

我想知道我做错了什么以及如何解决问题。我不想使用拆分功能。

谢谢,

汤姆。

4

7 回答 7

1

你给出的表达式太贪心,因此消耗的字符比你想要的多。以下表达式适用于您的示例数据集:

perl -l -ne '/:([^|]*)\|.*:([^|]*)\|/ and print($1,"\t",$2)'

":"它使用 a和"|"pair之间的明确匹配来锚定搜索。如果您的数据不完全匹配,它应该忽略输入行,但我没有对此进行测试。即,这个正则表达式假定在每行之间恰好有两个条目":"并且将存在。"|"

于 2012-08-28T14:40:10.373 回答
0

您指定它的方式,它必须以这种方式匹配。您想要一个冒号后跟任意数量的非管道,然后是任意数量的非冒号。

single colon -> :
non-pipe     -> Q9VNB0
non-colon    -> |intact
colon        -> :
non-pipe     -> EBI-102551   uniprotkb:A1ZBG6

相反,我将空格作为合同的结尾,并要求我的所有模式都以冒号开头,以竖线结尾并由非空格/非竖线字符组成。

perl -M5.010 -lne 'say join( "\t", m/[:]([^\s|]+)[|]/g )';
于 2012-08-28T15:35:14.140 回答
0

试试m/: ( [^:|]+ ) \| .+ : ( [^:|]+ ) \| /x吧。

于 2012-08-28T14:27:26.400 回答
0

解决方法可能是在第一个字符串和第二个字符串之间使用贪婪表达式。它.*一直到最后并开始回溯搜索最后一个冒号,后跟一个管道。

perl -l -ne '/:([^|]*).*:([^|]*)\|/ and print($1,"\t",$2)' <file>

输出:

Q9VNB0  A1ZBG6
P91682  Q24117
P92177-3        Q9VDK2
于 2012-08-28T14:30:08.503 回答
0
perl -nle'print "$1\t$2" if /:([^|]*)\S*\s[^:]*:([^|]*)/'

或 5.10+:

perl -nE'say "$1\t$2" if /:([^|]*)\S*\s[^:]*:([^|]*)/'

解释:

:          Matches the start of the first "word".
([^|]*)    Matches the desired part of the first "word".
\S*        Matches the end of the first "word".
\s+        Matches the "word" separator.
[^:]*:     Matches the start of the second "word".
([^|]*)    Matches the desired part of the second "word".

这不是最短的答案(尽管很接近),因为每个部分都完全独立于其他部分。这使它更健壮、更不容易出错并且更易于维护。

于 2012-08-28T16:15:47.990 回答
0

看看它在行动

:([\w\-]*?)\|

另一种方法:

:(\S*?)\|
于 2012-08-28T14:35:48.193 回答
0

为什么不想使用该split功能。从表面上看,这很容易通过编写来解决

my @fields = map /:([^|]+)/, split

我不确定您的正则表达式应该如何工作。使用/x修饰符来允许不重要的空格,它看起来像这样

/ : ([^|]*)? [^:]* : ([^|]*) /x

它找到一个冒号,并可以选择捕获尽可能多的非管道字符。然后将尽可能多的非冒号字符跳过到下一个冒号。然后尽可能多地捕获零个非管道字符。因为你的所有匹配都是贪婪的,所以只要字符匹配字符类,它们中的任何一个都可以消耗字符串的所有其余部分。请注意,?表示可选序列的 a 将首先匹配它所能匹配的所有内容,并且只有当模式的其余部分无法匹配时才会采用跳过该序列的选项

很难从您的示例中判断一个字段的精确标准,但是这段代码应该可以解决问题。它查找既不是冒号也不是管道的字符序列,这些字符以冒号开头并以管道结尾

use strict;
use warnings;

while (<DATA>) {
  my @fields = /:([^:|]+)\|/g;
  print join("\t", @fields), "\n";
}
__DATA__
uniprotkb:Q9VNB0|intact:EBI-102551   uniprotkb:A1ZBG6|intact:EBI-195768
uniprotkb:P91682|intact:EBI-142245   uniprotkb:Q24117|intact:EBI-156442
uniprotkb:P92177-3|intact:EBI-204491     uniprotkb:Q9VDK2|intact:EBI-87444

输出

Q9VNB0  A1ZBG6
P91682  Q24117
P92177-3    Q9VDK2
于 2012-08-28T18:21:56.283 回答