web-dev-qa-db-ja.com

タブ区切りファイルの列のテキスト文字列から最初の整数を抽出するにはどうすればよいですか?

私はMedicalGeneticsで働いており、多くの場合、区切り文字で区切られたテキストファイルがあり、1つの列(例:列5)に「突然変異」を含むテキスト文字列があります。
c.2458C>Tまたはc.45_46delAAまたはc.749_754delinsTG

同様に、別のファイルでは次のようになります。
p.Glu34*またはp.Ala78_Arg80delまたはp.L378Ffs*11

c.およびp.あるはずですが、省略される場合があります。数字以外の文字はいくつあってもかまいません。数字は常に整数で、通常は1〜14桁の長さです。

最初の例の2458、45、または749のように、最初の整数のみを持つ新しい列をファイルのどこかに追加したいと思います。次に、この整数をルックアップテーブルでいくつかの値を検索するためのキー値として使用します。

一部のファイルは70,000行あるため、手動で編集することはできません...

基本的なソリューションほど優れています。 bash、sed、またはawkで実行できますか?

テーブルの例は次のようになります(以下で正しく解釈されます)。

1       2       3       4       c.2458C>T
a   b   c   d   c.45_46delAA
a1  b2  c3  d4  p.Ala78_Arg80del

(注:列はスペース区切りではなく、タブ区切りです)

ヒトゲノム変異学会 によるこのフォーマットの仕様があります。この形式を使用するプログラムはありませんが(私は願っています!)、人々は出版物や医療レポートで使用しています。 Variant Call Format などの新しい形式が導入されました。これらははるかに解析可能です。

4
minnimalist

glennjackmanのGNU/AWKの答えはエレガントですが、もう少し簡単に言えば

awk 'BEGIN {FS=OFS="\t"} match($5,/[0-9]+/,arr) {print $0,arr[0]}' file
4
user2138595

あなたの説明に基づいて、入力として、次のようなタブ区切りのファイルがあるとします。

$ cat file
1       2       3       4       c.2458C>T       6
a       b       c       d       c.45_46delAA or f
a1      b2      c3      d4      p.Ala78_Arg80del        f6

Sedを使用する

5番目の列から最初の整数を見つけるには:

$ sed -r 's/([^\t]*\t){4}[^[:digit:]]*([[:digit:]]+).*/\2/' file
2458
45
78

上記はGNU sedでテストされました。OSXまたは他のBSDシステムの場合は、以下を試してください。

sed -E 's/([^\t]*\t){4}[^[:digit:]]*([[:digit:]][[:digit:]]*).*/\2/' file

Awkを使用する

$ awk '{sub(/^[^[:digit:]]*/, "", $5); sub(/[^[:digit:]].*/, "", $5); print $5;}' file
2458
45
78
4
John1024

@ John1024のサンプルテキストを使用すると、これはGNU-awk固有です

gawk -F '\t' -v OFS='\t' 'match($5, /[[:digit:]]+/, m) {$(++NF) = m[0]} 1' file

を生成します

1   2   3   4   c.2458C>T   6   2458
a   b   c   d   c.45_46delAA    or  f   45
a1  b2  c3  d4  p.Ala78_Arg80del    f6  78

またはPerl

Perl -F'\t' -lane 'print join "\t", @F, $F[4]=~/(\d+)/' file
4
glenn jackman

sedを使用すると、オカレンスで置き換えることができます-したがって、5番目を要求するだけです<\tab>-区切り [1] フィールドと、他の可能な一致を除外することによるその中の任意の数:

sed 's/[^\t0-9]*\([0-9]*\)[^\t]*/\1/5' <infile

ここで他の例をクリップボードにコピーした後、次のようにしました。

xsel -bo | unexpand -a | sed ...

... to unexpand-all <tab>-サイズのスペースシーケンスを実際の<tab>に。そしてそれは印刷されました...

1   2   3   4   2458    6
a   b   c   d   45
a1  b2  c3  d4  78  f6

...これは5番目の列の最初の整数を分離するだけです。しかし、それがあなたが望むものかどうかはわかりません。行の5番目の列の最初の整数だけが必要な場合は、はるかに簡単です(そしてはるかに高速です)

<infile \
 cut -f5 | tr -cs '0-9\n' \\t |
 expand -t1,2,4 | cut -d' ' -f-2

...最初のcuts5番目の<tab>-区切り [2] 1行あたりのデータフィールド全体(フィールドあたりの複数の整数によって引き起こされる可能性のある問題を回避するため)その後、translatesを1つに<tab> every -squeezedシーケンスの文字-c\newlinesおよび0-9標準数字 のセットの補足 [3]

これは、出力では、最初の整数が最初のフィールドまたは2番目のフィールドのいずれかにあることを意味します-最初のフィールドが空になっているため(<tab>が主導)または数字シーケンス(お気づきのように接頭辞が付いていました。したがって、私はexpand1番目と2番目のcd <tab>-行の位置を1つのスペースに停止し、3番目をスペースに停止します-これにより、スペースのリストが効果的に埋められます-空の最初のフィールドまたは空の3番目のフィールドを持つようにフィールドを区切ります。そこから、最初の2つのフィールドをcutすることができます。

 2458
 45
 78

...すべてが[cp]。でリードされていたため、使用した例の結果でした。したがって、すべてがリード<tab> sでしたが、そうでないものはずらされていました。左に。さらに、すべての結果を1行に凝縮し、各整数を1つのスペースで区切るには、コマンドに|xargsを追加して、代わりに次のようにします。

2458 45 78

メモ

  1. \tエスケープは、sedが関係する標準のエスケープではないことに注意してください。また、[bracket-expression]文字クラスのコンテキストでは、\の標準とは明らかに反対です。 SOMECODE] _backslash文字とt文字は、それぞれ自分自身を表す必要があります。ここでは、読みやすい意図をより明確に示すためにエスケープを使用しましたが、代わりにリテラル<tab>を使用する必要があります。

  2. cutはデフォルトで<tab>文字で区切られているため、この場合、一般的な-d [delim-char]オプションは不要ですが、理由を説明するためにこのメモも追加しました。

  3. リンクに記載されているように、POSIX標準では、[:digit:]文字クラスにすべてのロケールで123456789文字が含まれ、その並べ替え順序で、そのクラスの他の包含よりも先に並べ替えられる必要があります。 。非Cロケールには、他のローカライズされた数字セットも含まれる場合があります-a GNU trは、複数のバイトで表される可能性があるため、おそらく適切に処理されません-しかしのみとにかくほとんどの場合、標準の数字セットは最も驚くべき結果ではない可能性が高いので、間違いなく標準のアラビア数字セットといくつかの文字の両方の文字を一致させたい場合を除いて、[:digit:]を使用しますotherロケールに依存する数字のセットはおそらくお勧めできません。

1
mikeserv