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


17

次のような行があるとしましょう:

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

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

より一般的には、このことは、これらのツールのcutsedgrepまたはawk、そのような作業に適しているでしょうか?

回答:


16

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

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

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

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

sedでは、で印刷をオフにし-n、行全体を一致させ、一致する部分のみを保持する必要があります。1行に複数の一致が考えられる場合、最後の一致のみが出力されます。参照してください。周囲の文字を印刷せずに「セッド」でマッチした正規表現の抽出ここでの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'

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


彼は「括弧内の数字抽出する」ことを望んでいること以外は、すべて良いです。「除く[number]」とは次のことを意味すると思う[0-9]
Peter.O

1
@ Peter.OIは、「[number]を除く」とは、そのフォームの行に他の部分がないことを意味すると理解していました。しかし、念のため、数字だけを印刷する方法を示すために回答を編集しました。
ジル 'SO-悪であるのをやめる

1
これらのperl正規表現は本当に便利に見えます!grepであっても、後方アサーションと前方アサーションの両方を使用するのを見た後、私はそれらについて読んでいます(正規表現エンジンを選択できるという事実に切り替えました)。これから、perlの正規表現にもう少し時間を費やします。おかげで... PS ..ただ読みましたman grep... "これは非常に実験的であり、grep -Pは未実装の機能について警告するかもしれません。" ...不安定ではないことを願っています(?)...
Peter.O

5

あなたはそれを行うことはできません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 は問題に最も自然に適合し、おそらく最速で実行されますが、速度の点でこれらのオプションを分離するには巨大な入力が必要になると思います。


sedの場合、^.*貪欲で最後の数字以外をすべて消費し、posixを使用する+必要があり\+ます\([0-9][0-9]*\)... またはいずれの場合も同様に's/[^0-9]*//g'動作します、... Thanks for the tr -c`の例ですが、その末尾は\012過剰ではありませんか?
Peter.O

@Peterキャッチしてくれてありがとう。私はsedの例をテストしたと誓っていたでしょう。:(私はあなたのバージョンに変更しましたに関して。\012:そうでない場合は必要とされているtr。改行を食べるようになる
カイル・ジョーンズ

なるほど...私はそれを見ていた\012(あるいは、\、0、1、2)。8進数に十分に順応していないようです。ありがとう。
Peter.O

4

数字以外の文字の間の連続した数字のセットを抽出することを意味する場合、私は推測sedawk、最高です(ただしgrep、一致した文字を与えることもできます):

sed:もちろん数字を一致させることはできますが、逆のことをして、数字以外を削除するのは面白いかもしれません(1行に1つの数字しかない限り)。

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

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

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

awk経験がないので、例を挙げません。sedスイスナイフgrepですが、これを行うためのより簡単で読みやすい方法を提供することに注意することは興味深いです。これは、各入力行で複数の数字に対しても機能します(入力-oの一致する部分のみを印刷します。独自の行で):

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

ちょうど比較として、ここに「行ごとに複数の数字」の例とsed同等のものがあります。。。...(+1)grep -o '[[:digit:]]*'sed -nr '/[0-9]/{ s/^[^[0-9]*|[^0-9]*$//g; s/[^0-9]+/\n/g; p}'
Peter.O

2

「これはできない」と言われているので、「ベスト」としてのcut使用を推奨していなくても、少なくとも他のソリューションよりも悪くないソリューションを簡単に作成できることを示しcutます。 (または特に良い)ソリューション。数字*[]*その周辺を特に探していないソリューションは、仮定を単純化するため、アスカーによって与えられたものよりも複雑な例で失敗する傾向があると言われるべきです(例えば数字*[]*、表示されない)。このソリューションは、少なくとも括弧をチェックし、アスタリスクもチェックするように拡張できます(読者への演習として残しました)。

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

これは-d、区切り文字を指定するオプションを使用します。もちろんcut、ファイルから読み取る代わりに式にパイプすることもできます。一方でcut、それは(なし正規表現エンジン)簡単であるため、かなり速いおそらく、あなたはそれを起動する必要が二回以上(またはかどうかを確認するには、いくつかのより多くの時間で*)いくつかのプロセスのオーバーヘッドを作成し、。このソリューションの1つの本当の利点は、特に正規表現の構造に精通していないカジュアルなユーザーにとって、かなり読みやすいことです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.