各列の行から部分文字列を抽出する

各列の行から部分文字列を抽出する

次のように、20,000行を超えるテキストファイルがあります。

7   128550681   128550681   Intron:1:36:RETAINED-RETAINED;Transcript:NM_001135914.1;Gene:KCP:protein_coding 1   1   0   0
1   17718672    17718672    Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding  1   1   0   0
1   17718672    17718672    Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding  1   1   0   0
4   86035   86035   Exon:4:5:RETAINED;Transcript:NM_001286052.1;Gene:ZNF595:protein_coding  1   1   0   0
3   12942851    12942851    Intron:14:14:SKIPPED-ALTTENATIVE_3SS;Transcript:NM_001134382.2;Gene:IQSEC1:protein_coding   1   1   0   0

必要なのは、4番目の列にGene:genenameのみが含まれているため、出力は次のようになります。

7   128550681   128550681   Gene:KCP    1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
4   86035   86035   Gene:ZNF595 1   1   0   0
3   12942851    12942851    Gene:IQSEC1 1   1   0   0

Gene:genename*:押したり分割したりすると、問題は常に同じ場所に表示されません。;

私は特定の列を選択する方法、特定のパターンを含む行を見つける方法など、非常に基本的なawk / sedを知っています。

答え1

awk次のコマンドを使用してこれを実行できました。

awk '{sub(/^.*;/,"",$4); print}' input

これにより、最後の項目までの列4の内容がすべて削除され、機能しなくなる可能性があり;ます(Steeldriverの説明を参照)。この場合は、明確な説明を含む質問を更新してください。

答え2

awkPOSIX 定義構造にのみ使用されます。

awk 'match($4, /Gene:(.+)\:/){ $4=substr($4, RSTART, RLENGTH-1) }1' file

出力をより整理するには、出力をタブ区切りの| column -t列にパイプします。場所がわからない場合は、パターンをGene:genename変更してawk行内の任意の場所を見つけて、4番目の列を希望の値に変更します。$4(フルライン)に変更すると$0正常に動作します。

awk 'match($0, /Gene:(.+)\:/){ $4=substr($0, RSTART, RLENGTH-1) }1' file

答え3

perl -pale 's#(?:\H+\h+){3}\K\H+#($F[3] =~ /(?:^|;)(Gene:[^:]+)/)[0]#e' input-file.txt 

°4番目のフィールドの遺伝子位置が固定されていない場合は、上記のように動作できます。

°正規表現で4番目のフィールドをゼロにし、コマンド(?:\H+\h+){3}\K\H+置換セクションで使用されている他の正規表現にすぐに置き換えますs///e

答え4

真珠:

perl -F'\h+' -lane '
    for ( $F[3] ) {
        my $a = index(";$_", ";Gene:"     );
        my $b = index(";$_", ":",    $a+6 );
        $_ = substr(";$_", $a+1, $b-$a-1);
    }
    print join "\t", @F;
' input-file.txt

出力:

7   128550681   128550681   Gene:KCP    1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
4   86035   86035   Gene:ZNF595 1   1   0   0
3   12942851    12942851    Gene:IQSEC1 1   1   0   0
$   128550681   128550681   Gene:$$$    1   1   0   0

説明する:

  • perlオプション:
    • -n=>入力内容を1行ずつ読み込むように呼び出します。
    • -F=>作成しますFS = horizontal whitespace
    • -a=>各行をフィールド(-Fオプション設定に応じてFSまたはデフォルトで単一のスペース)に分割し、配列に保存します@F
    • -l=>作成しますRS = ORS = "\n"
    • -e=>次の内容はPerlコードとして扱われ、すべての行、つまりレコードに適用されます。
  • data structures関連:
    • @F=> レコードを分割して得られたフィールドで埋められた配列。インデックスは0から始まります。$F[3]レコードの4番目のフィールドにも同様です。
    • $a;Gene:=> 4番目のフィールドに部分文字列の位置を保存します。
    • $b=>部分文字列の位置を4番目のフィールドに保存すると、その:位置の後に6桁を見つけることができます;Gene:。 IOW、:次に2番目を見つけました;Gene。注:検索文字列にセミコロンを入力します。つまり、$F[3]場所はGene:どこにでもある可能性があるため、4番目のフィールドの先頭にもあります。これはこの可能性に対処するためのものです。
    • $_$F[3]=>ループ内にローカライズされたバージョンを保存しますfor。内蔵機能は情報をsubstr抽出して再保存します。gene:...$F[3]
    • 注:my変数定義の前の修飾子は、$a,$bそれを範囲がループに制限される語彙変数として表示しますfor
    • 注:現在のレコード/行はループ$_内で参照されません。forループ期間for$F[3]

GNU Sed:

sed -Ee '
    s/\S+/\n&\n/4
    s/\n(.*;)?(Gene:[^:]+):.*\n/\2/
' input-file.txt

説明する:

  • 4番目のフィールドを改行文字で表示します。
  • 現在行の領域を杭打ちした後、必要なデータ(この場合)を見つけてくださいGene:as many non colons we meet on the way before we hit the next colon
  • この方法は、個々のフィールド間に存在する間隔を妨げません。これは重要かもしれませんし、重要ではないかもしれません。
  • 注:注:4番目のフィールドに遺伝子があるとします。複数の遺伝子の場合は、エラーや警告を表示せずに、レコードの4番目のフィールドにある最後の遺伝子を自動的に選択します。

関連情報