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

2 つの列の間はタブで区切られています。私は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と"|"ペアの間の何かに対する明示的な一致で検索を固定します。データが正確に一致しない場合、入力行無視されますが、これはテストしていません。つまり、この正規表現は、行ごとに と の間に正確に 2 つのエントリが存在することを前提として":""|"ます。

于 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
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 に答える
0

修正は、最初の文字列と 2 番目の文字列の間で欲張り表現を使用することです。.*最後まで行き、最後のコロンとそれに続くパイプを探してバックトラックを開始します。

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

出力:

Q9VNB0  A1ZBG6
P91682  Q24117
P92177-3        Q9VDK2
于 2012-08-28T14:30:08.503 に答える
0

m/: ( [^:|]+ ) \| .+ : ( [^:|]+ ) \| /x代わりに試してください。

于 2012-08-28T14:27:26.400 に答える