2017-11-20 17 views
2

以下のファイルでは、「XC:Z:」と「XM:Z:」の2つの文字列を抽出します。たとえば:1行に複数の正規表現マッチを抽出する

  • 1行目の出力はこのようになります "TGGTCGGCGCGT、GAGTCCGT"
  • 2行目の出力はこのようになります "GAAGCCGCTTCC、ACCGACGG"

ファイルの元のバージョンがありもしまた

MOUSE_10  XC:Z:TGGTCGGCGCGT  RG:Z:A XM:Z:GAGTCCGT ZP:i:33 
    MOUSE_10  XC:Z:GAAGCCGCTTCC  NM:i:0 XM:Z:ACCGACGG AS:i:16 
    MOUSE_10  ZP:i:36 XC:Z:TCCCCGGGTACA  NM:i:0 XM:Z:GGGACGGG ZP:i:28 
    MOUSE_10  XC:Z:CAAATTTGGAAA  RG:Z:A NM:i:1 XM:Z:GCAGATAG 

、以下の基準のそれぞれは、ボーナスになりますが、必須ではありません。次の例よりも多くの列と行数百万、数が、それはあなたのアイデアを与える必要がありますあなたはそれが仕事を得ることができます:

  • 使用標準のbashツール:AWK、sedは、grepを、など(無GAWK、csvtools、...)
  • は、私たちがどのXC順序を知っていないと仮定しますXMが現れます(XCはほぼ確実ですが、確認方法は不明です)。ただし、出力では、XC文字列は可能な限りXM文字列の前にある必要があります。

awk extract multiple groups from each lineの回答は非常に近くにありますが、match(...)を使用するときはいつでも「予期しないトークンに近い構文エラー」というメッセージが表示されます。

あなたのソリューションを楽しみにしています! awk解決後

おかげで、

フェリックス

+0

「GAWK」で簡単に – RomanPerekhrest

+2

エラーが発生したコードを表示する必要があります。これは簡単に修正できます。 –

+0

'XC:Z:'の3ロットと 'XM:Z:'の2ロットを一行で得ることができますか?あなたは他のパターンなしで1つのパターンを持つことができますか?プレフィックスを保持する必要がありますか? 1つの入力行に2つ以上の一致があっても、出力にパターンごとに1行が必要なので、出力の行の総数は入力の行数よりも大きくなる可能性があります。それは難しいことではありません。それはちょうどあなたがしたいことを正確に働くことの単なる問題です。サンプル出力データを使ってMCVE([MCVE])を作成する(入力が良好であることがわかります)。 –

答えて

0

は同じであなたを助けるかもしれません。

awk ' 
/XC:Z:/{ 
    match($0,/XC:[^ ]*/); 
    num=split(substr($0,RSTART,RLENGTH),a,":"); 
    match($0,/XM:[^ ]*/); 
    num1=split(substr($0,RSTART,RLENGTH),b,":"); 
    print a[num],b[num1] 
}' Input_file 

出力は以下の通りです。

TGGTCGGCGCGT GAGTCCGT 
GAAGCCGCTTCC ACCGACGG 
TCCCCGGGTACA GGGACGGG 
CAAATTTGGAAA GCAGATAG 
+0

RavinderSingh13ありがとうございました。私はあなたの答えが好きで、もう少し理解したいと思います。 a、b、num、num1のどの値を取っているのか説明できますか?私はaとbがsplitコマンド内で作成されている配列であると仮定しますが、それは正しいですか? – Felix

1

あなたはXC:Z:XM:Z後に非空白文字をキャプチャすることができsedのでは:

sed -n 's/.*XC:Z:\([^[:blank:]]*\).*XM:Z:\([^[:blank:]]*\).*/\1, \2/p;' file 

あなたが逆の値について秒sコマンドを追加することができます。

sed -n 's/.*XC:Z:\([^[:blank:]]*\).*XM:Z:\([^[:blank:]]*\).*/\1, \2/;s/.*XM:Z:\([^[:blank:]]*\).*XC:Z:\([^[:blank:]]*\).*/\1, \2/;p;' file 
+0

ありがとう@SLePort、これは私のために必要なものです。私はこれがXCを前提としていることを理解しています:Z:常に 'XM:Z:'の前にあります。 – Felix

+0

'XM:Z'が' XC:Z'の前にある場合をカバーするように編集しました。 – SLePort

0

awk

$ awk '{c=p="";        # need to reset c and p before each line 
     for(i=1;i<=NF;i++)     # for all fields in the line 
      if($i~/^XC:Z:/) c=substr($i,6)  # check pattern from the start of field 
      else if($i~/^XM:Z:/) p=substr($i,6) # if didn't match check other other pattern 
     if(c && p) print c,p}' file   # if both matched print 

TGGTCGGCGCGT GAGTCCGT 
GAAGCCGCTTCC ACCGACGG 
TCCCCGGGTACA GGGACGGG 
CAAATTTGGAAA GCAGATAG 

同じ行に複数のインスタンスがある場合、これは最後の一致を出力します。わずかに異なる特性を持つ別のものがここにあります。

$ awk 'function s(x) {return ($i~x)?substr($i,6):""} 
     {c=p=""; 
     for(i=1;i<=NF;i++) { 
     c=c?c:s("^XC:Z:"); p=p?p:s("^XM:Z:"); 
     if(c && p) 
      {print c,p; next}}}' file 

TGGTCGGCGCGT GAGTCCGT 
GAAGCCGCTTCC ACCGACGG 
TCCCCGGGTACA GGGACGGG 
CAAATTTGGAAA GCAGATAG 

これは、他のものとの最初の一致の前に繰り返される一致の最後を印刷します。それらはペアで表示され、最初のペアが印刷されます。

+0

こんにちは@karakfa、本当にあなたのsolution1のように、私のファイルでうまくいくようです、ありがとう。私には3つのことが不明です。まず、forループの中ではなく、cとp(c = p = "")をリセットするべきではありませんか?第二に、なぜ「if」の代わりに「else if」を使うのですか? 3つ目のポイントは、 '^'記号は通常行頭を表していないのですか?そうであれば、その前には少なくとも1つの列( "Mouse_10")がありますが、ここでどのように機能しますか? (#3はGoogleにはあまりにも怠惰で、私に正規表現を説明するのを忘れないと無視してもいいですが、#1と#2は解決するのが良いでしょう!) – Felix

+0

説明を追加しました。 'else else'は一度に一つのパターンにしかマッチできないので、それが前のパターンにマッチするならば、他のものをチェックする必要はないので、より良いです。この解決策があなたの質問を解決した場合は、議決権を必要とするか、答えとして選択する必要があります。 – karakfa

0

我々はXCとXMが 表示されますが、これはsedを試すことができた順番がわからない場合は

sed -E 'h;s/(XC:Z:.*XM:Z:)//;tA;x;s/(.*XM:Z:)([^[:blank:]]*)(.*XC:Z:)([^[:blank:]]*)(.*)/\4,\2/;b;:A;x;s/(.*XC:Z:)([^[:blank:]]*)(.*XM:Z:)([^[:blank:]]*)(.*)/\2,\4/' infile 

説明:

sed -E ' 
h 
# keep the line in the hold space 
s/(XC:Z:.*XM:Z:)//;x;tA 
# if XCZ come before XMZ, go to A but before everything restore the pattern space with x 
s/(.*XM:Z:)([^[:blank:]]*)(.*XC:Z:)([^[:blank:]]*)(.*)/\4,\2/ 
# XMZ come before XCZ, get the interresting parts and reorder it 
b 
# It is all for this line 
:A 
s/(.*XC:Z:)([^[:blank:]]*)(.*XM:Z:)([^[:blank:]]*)(.*)/\2,\4/ 
# XCZ come before XMZ, get the interresting parts 
' infile 
+0

このコードは何をすべきかを行い、説明は非常に便利です。ありがとう!そして私はあなたの信じられないほどのうつ病のスキルに直面して驚いています。 – Felix

0

はPOSIX awkを使用して、あなただけの文字列を使用することができます機能match(s,ere)は、IEEE Std 1003.1-2008によって定義される:

match(s, ere)

戻り、それが全く生じない場合 ストリング拡張正規表現EREが発生S、またはゼロで、1から番号文字位置、、。 RSTARTは、開始位置 (戻り値と同じ)に設定され、一致するものが見つからない場合は0に設定されます。 RLENGTHは一致する文字列の長さに設定され、一致する文字列が見つからない場合は-1が設定されます。

一致するパターンはXM:Z:[^[:blank:]]*XC:Z:[^[:blank:]]*です。しかしこれは、PXM:Z:のような文字列がないことを前提としています(つまり、空白以外の文字が検索された文字列を進める)。パターンが行$0に見つかると、5文字後に始まる重要な部分のみを抽出するだけです。

次のコードは、上記の処理を行います。

awk '{match($0,/XM:Z:[^[:blank:]]*/);xm=substr($0,RSTART+5,RLENGTH-5)} 
     {match($0,/XC:Z:[^[:blank:]]*/);xc=substr($0,RSTART+5,RLENGTH-5)} 
     {print xc","xm}' <file> 

あなたが見ることができるように、最初の行はXM抽出し、カンマ区切り","と第XC及び第三の印刷結果。

備考 - 以下の仮定がここで作られています:あなたが使用して喜んでいる場合

  • 各行が​​とxc文字列
  • の両方が含まれているタイプ[^[:blank:]]X[CM]:Z:[^[:blank:]]*の無い文字列が

存在しますgawkの場合、文字列操作にpatsplit関数を使用できます(Ref。here)。これは、1つの正規表現/X[CM]:Z:[^[:blank:]]*/で行うことができます。これにより、XM:Z:またはXM:C:部分を含む1回の呼び出しで、要求された文字列が直接得られます。その後、簡単にソートして最後の部分を抽出することができます。

次の行がgawkそれでも

gawk '{patsplit($0,a,/X[MC]:Z:[^[:blank:]]*/) } 
     {xc=(a[1]~/^XC/)?a[1]:a[2]; xm=(a[1]~/^XC/)?a[2]:a[1]} 
     {print substr(xc,5)","substr(xm,5)' <file> 

でまったく同じ操作を行い、私はawkソリューションは、ビューの対称性の点から、クリーンであると考えています。

関連する問題