web-dev-qa-db-ja.com

2つの特定の文字または文字列の間のテキストを検索する

次のような行があるとします。

*[234]*
*[23]*
*[1453]*

ここで、*は任意の文字列を表します([number]形式の文字列を除く)。コマンドラインユーティリティでこれらの行を解析し、角かっこで囲まれた数を抽出するにはどうすればよいですか?

より一般的には、これらのツールのcutsedgrepまたはawkは、このようなタスクに適していますか?

17

GNU grepがある場合は、その-oオプションを使用して正規表現を検索し、一致する部分のみを出力できます(他のgrep実装では行全体しか表示できません)。 1行に複数の一致があり、それらは別々の行に出力されます。

grep -o '\[[0-9]*\]'

角かっこではなく数字のみが必要な場合は、少し難しくなります。幅がゼロのアサーションを使用する必要があります。空の文字列に一致する正規表現ですが、前に、または場合によっては後にブラケットがある場合に限ります。ゼロ幅アサーションは、Perl構文でのみ使用できます。

grep -P -o '(?<=\[)[0-9]*(?=\])'

Sedでは、-nで印刷をオフにし、行全体を一致させ、一致した部分のみを保持する必要があります。 1行に複数の可能な一致がある場合、最後の一致のみが出力されます。ここでsedを使用する方法の詳細については、 「sed」に一致する正規表現を、周囲の文字を印刷せずに抽出する を参照してください。

sed -n 's/^.*\(\[[0-9]*\]\).*/\1/p'

かっこではなく数字のみが必要な場合:

sed -n 's/^.*\[\([0-9]*\)\].*/\1/p'

grep -oがなければ、Perlは、シンプルでわかりやすいものが必要な場合に最適なツールです。すべての行(-n)で、その行に\[[0-9]*\]の一致が含まれている場合は、その一致($&)と改行(-l)を出力します。

Perl -l -ne '/\[[0-9]*\]/ and print $&'

数字だけが必要な場合は、正規表現に括弧を入れてグループを区切り、そのグループのみを印刷します。

Perl -l -ne '/\[([0-9]*)\]/ and print $1'

追伸大括弧の間に1桁以上の数字のみを必要とする場合は、[0-9]*[0-9][0-9]*に変更するか、Perlで[0-9]+に変更します。

cutではできません。

  1. tr -c -d '0123456789\012'
  2. sed 's/[^0-9]*//g'
  3. awk -F'[^0-9]+' '{ print $1$2$3 }'
  4. grep -o -E '[0-9]+'

trが問題に最も自然に適合し、おそらく最も速く実行されますが、これらのオプションのいずれかを速度の観点から分離するには、巨大な入力が必要になると思います。

5
Kyle Jones

数字以外の文字の間の連続する数字のセットを抽出することを意味する場合、sedawkが最適だと思います(ただし、grepも一致した文字を提供できます) ):

sed:数字を一致させることはもちろん可能ですが、反対のことを行って、数字以外を削除することは興味深いでしょう(1行に1つの数字しかない限り機能します)。

$ echo nn3334nn | sed -e 's/[^[[:digit:]]]*//g'
3344

grep:連続する数字を照合できます

$ echo nn3334nn | grep -o '[[:digit:]]*'
3344

awkの例は示していません。これは、Nullの経験があるためです。興味深いことに、sedはスイスナイフですが、grepを使用すると、これをより簡単で読みやすくすることができます。これは、各入力行で複数の数値に対しても機能します( -oは、入力の一致する部分のみを出力します。各部分は1行に表示されます):

$ echo dna42dna54dna | grep -o '[[:digit:]]*'
42
54
4
njsg

これはcutでは実行できないと言われているので、使用を推奨していなくても、他のいくつかのソリューションよりも悪くないソリューションを簡単に作成できることを示します。 cutを「最良の」(または特に優れた)ソリューションとして。数字の周りで*[]*を特に探していないソリューションは、仮定を単純化するため、質問者によって与えられた例よりも複雑な例で失敗する傾向があります(例:*[]*の外側の数字は表示されません)。 )。このソリューションは、少なくともブラケットをチェックし、アスタリスクもチェックするように拡張できます(読者への演習として残しました)。

cut -f 2 -d '[' myfile.txt | cut -f 1 -d ']'

これは、区切り文字を指定する-dオプションを利用します。もちろん、ファイルから読み取る代わりに、cut式にパイプすることもできます。 cutは非常に高速ですが、シンプル(正規表現エンジンなし)なので、少なくとも2回(または*を確認するためにさらに数回)呼び出す必要があり、プロセスのオーバーヘッドが発生します。このソリューションの1つの真の利点は、特に正規表現の構造に精通していないカジュアルなユーザーにとっては、かなり読みやすいことです。

2
Thomas