n桁のグループをgrepする方法(ただし、n以下)


33

私はLinuxを学んでいますが、自分で解決できないように思える課題があります。ここにあります:

grepは、1行に4つの数字を含むが4以下のファイルから1行をgrepします。

私はこれにどのようにアプローチするかわかりません。特定の数値を検索することはできますが、文字列でその数値を検索することはできません。


2
のような行を1234a12345表示する必要がありますか?
エリアケイガン14年

@Buddhaは、例とともに質問を説明する必要があります。
アビナッシュラジ

数字の前にスペースまたは行アンカーの先頭があり、その後にスペースまたは行アンカーの末尾が続く場合、単に単語の境界を使用できます。\b\d{4}\b
アビナッシュラジ14年

1
この質問は、正規表現に関するいくつかの質問とは異なり、grepの使用について明確になっています。Ubuntuでgrep、sed、awkなどのUnixユーティリティを使用することに関する質問は、ここでは常に適切であると考えられてきました。時々、人々は間違ったツールで仕事をする方法を尋ねます。コンテキストの欠如は大きな問題ですが、それはここで起こっていることではありません。これはトピックに沿ったものであり、有用な回答を得るのに十分なほど明確であり、コミュニティにとって有益であり、さらなる回答を妨げたり、削除または移行に向けてプッシュしたりするメリットはありません。私はそれを再開することに投票しています。
エリアケイガン14年

1
どうもありがとうございました、私はこれほど多くのフィードバックを得るとは思いませんでした。これは私が探していた答えです:grep -E '(^ | [^ 0-9])[0-9] {4}($ | [^ 0-9])'ファイル。このコマンドは、次のような文字列を取得できる必要があります(実行します):abc1234abcd99999
Buddha

回答:


52

この質問を解釈する方法は2つあります。両方のケースに対処します。行を表示したい場合があります。

  1. それ自体がより長い数字のシーケンスの一部ではない4桁のシーケンスを含む、または
  2. これには4桁のシーケンスが含まれていますが、数字のシーケンスは含まれていません(個別にではありません)。

たとえば、(1)はを表示します1234a56789が、(2)は表示しません。


それ自体が長い数字のシーケンスの一部ではない4桁のシーケンスを含むすべての行を表示する場合、1つの方法は次のとおりです。

grep -P '(?<!\d)\d{4}(?!\d)' file

これは、Ubuntu (GNU grep)がサポートするPerl正規表現を使用します。のようなテキストとは一致しませんし、その一部であるまたはにも一致しません。しかし、それはに一致ます。grep-P123451234234512341234a56789

Perlの正規表現では:

  • \dは任意の数字を意味します([0-9]またはを言う短い方法[[:digit:]]です)。
  • x{4}x4回一致します。({ }構文はPerlの正規表現に固有のものではありません。拡張正規表現でgrep -Eも同様です。)ですから\d{4}、と同じ\d\d\d\dです。
  • (?<!\d)は、幅がゼロの負の後読みアサーションです。「\d。が前にない限り」という意味です。
  • (?!\d)ゼロ幅の負の先読みアサーションです。「後に続く場合を除いて」を意味し\dます。

(?<!\d)また(?!\d)、4桁のシーケンス外のテキストとは一致しません。代わりに、より長い一連の数字の一部である場合、(一緒に使用すると)4桁の数字が一致するのを防ぎます。

右端または左端の4桁のサブシーケンスがまだ一致するため、後読みのみまたは先読みのみを使用するだけでは不十分です。

読みおよび先読みアサーションを使用する利点の1つは、パターンが周囲のテキストではなく、4桁のシーケンスのみと一致することです。これは、色の強調表示(--colorオプションを使用)を使用する場合に役立ちます。

ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4

Ubuntuのデフォルトでは、各ユーザーのファイルにalias grep='grep --color=auto'はがあり~.bashrcます。そのため、grepエイリアスが展開されるとき)で始まる単純なコマンドを実行すると、自動的に色が強調表示され、標準出力ターミナルになります(これがチェック対象です)。一致は通常、赤の色合い(朱色に近い)で強調表示されますが、斜体の太字で示しています。スクリーンショットは次のとおりです。--color=auto
出力として12345abc789d0123e4を含むそのgrepコマンドを示すスクリーンショット。0123が赤で強調表示されています。

またgrep、行全体ではなく、一致するテキストのみを印刷することもできます-o

ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123

先読みアサーションなしの代替方法

ただし、次の場合:

  1. また、システム上で実行されるコマンド必要grepサポートしていない-Pか、そうでない場合はPerlの正規表現を使用したくないし、そして
  2. 特に4桁を一致させる必要はありません-あなたの目標は、単に試合を含む表示ラインにある場合、通常はそうである、
  3. 少しエレガントではないソリューションで大丈夫です

...次に、代わりに拡張正規表現を使用してこれを実現できます。

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

これは、それらを囲む4桁の数字と数字以外の文字(または行の先頭または末尾)に一致します。具体的には:

  • [0-9]任意の数字(など[[:digit:]]、または\dPerlの正規表現)に一致し、{4}「4回」を意味します。したがって[0-9]{4}、4桁のシーケンスに一致します。
  • [^0-9]0〜の範囲にない文字に一致し9ます。[^[:digit:]]\DPerlの正規表現では)と同等です。
  • ^[ ]かっこで囲まれていない場合、行の先頭に一致します。同様に$、行末に一致します。
  • |手段または括弧は(代数のように)グループ化されています。したがって(^|[^0-9])、行の先頭または数字以外の文字と($|[^0-9])一致し、行の末尾または数字以外の文字と一致します。

したがって、一致[0-9]{4}は、同時に4桁のシーケンス()を含む行でのみ発生します。

  • 行の先頭又は(非数字が先行する(^|[^0-9]))、及び
  • 行末または非数字(($|[^0-9]))が続きます。

一方、4桁のシーケンスを含むすべての行を表示したいが、4桁を超えるシーケンスを含まない場合(4桁のみの別のシーケンスとは別のものでも)、概念的には目標は、あるパターンに一致するが別のパターンには一致しない行を見つけることです。

したがって、1つのパターンでそれを行う方法を知っていても、2つのパターンを別々に使用して、マットの 2番目の提案のようなものを使用することをお勧めしますgrep

Perlの正規表現の高度な機能を使用する場合、それを行う際に大きなメリットは得られないため、使用しないほうがよい場合があります。しかし、上記のスタイルに合わせて、以下の代わりに(およびブレース)を使用したmattのソリューションの短縮版を次に示し\dます[0-9]

grep -P '\d{4}' file | grep -Pv '\d{5}'

を使用しているため[0-9]mattの方法はより移植性が高く、grepPerlの正規表現をサポートしていないシステムで動作します。の代わりに[0-9](または[[:digit:]]\dを使用し{ }、を使用し続けると、マットの方法の移植性がもう少し簡潔になります。

grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'

別の方法、単一パターン

あなたが本当にgrepコマンドを好む場合

  1. 単一の正規表現を使用します(上記のようにgrepパイプで区切られた2 つではありません)
  2. 4桁のシーケンスを少なくとも1つ含む行を表示するには、
  3. ただし、5桁以上のシーケンスはありません。
  4. そして、数字だけでなく、行全体を一致させることを気にしません(おそらくこれを気にしません)

...次に使用できます:

grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file

この-xフラグはgrep、行全体が一致する行のみを表示します(一致を含む行ではなく)。

Perlの正規表現を使用したのは、この場合の簡潔さ\d\D実質的な明瞭さが向上するからです。ただし、grepサポートしていないシステムに移植可能なものが必要な-P場合は、それらを[0-9]and [^0-9](または[[:digit:]]and [^[:digit]])に置き換えることができます。

grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file

これらの正規表現の機能は次のとおりです。

  • 中央、\d{4}または[0-9]{4}4桁の1つのシーケンスに一致します。これらは複数ある場合もありますが、少なくとも1つ必要です。

  • 左側、(\d{0,4}\D)*または4桁以下の非数字が続く([0-9]{0,4}[^0-9])*0個以上の(*)インスタンスに一致します。ゼロ桁(つまり、何もない)は、「4桁以下」の可能性の1つです。これはマッチ()空の文字列または(b)の任意の文字列終了非数字で以上4桁の任意の配列を含みません。

    中央\d{4}(または[0-9]{4})のすぐ左のテキストは空か、数字以外で終わる必要があるため、中央のすぐ左に\d{4}別の(5番目の)数字がある4桁と一致しないようにします。

  • 右側、(\D\d{0,4})*または非数字の([^0-9][0-9]{0,4})*ゼロ個以上(*)に一致し、その後に4桁以下の数字が続きます(前と同様に、4、3、2、1、またはまったくない場合もあります)。このマッチ()空の文字列または(b)の任意の文字列から始まる数字以外にし、4桁以上の任意のシーケンスを含みません。

    中央\d{4}(または[0-9]{4})のすぐ右のテキストは空にするか、数字以外で始まる必要があるため、中央のすぐ右に\d{4}別の(5番目の)数字がある4桁と一致しないようにします。

これにより、4桁のシーケンスがどこかに存在し、5桁以上のシーケンスがどこにも存在しないことが保証されます。

この方法で行うことは悪くも間違っていません。しかし、おそらくこの代替案を検討する最も重要な理由は、上記およびmattの回答で示唆されているように、代わりに(または同様の)使用の利点を明確にすることです。grep -P '\d{4}' file | grep -Pv '\d{5}'

そのようにして、あなたの目標は、あるものを含むが別のものを含まない行を選択することであることは明らかです。さらに、構文は単純です(そのため、多くの読者/保守者がより早く理解できるかもしれません)。


9

これにより、4つの数字が連続して表示されますが、それ以上は表示されません

grep '[0-9][0-9][0-9][0-9][^0-9]' file

^は意味しないことに注意してください

これには問題がありますが、修正方法がわかりません...番号が行末であれば、表示されません。

ただし、このいバージョンはその場合に機能します

grep '[0-9][0-9][0-9][0-9]' file | grep -v [0-9][0-9][0-9][0-9][0-9]

おっと、egrepである必要はありません
マット14年

2
最初のものは間違っています- a12345b一致するため、見つけ2345bます。
フォルカーシーゲル14年

0

grepperlの正規表現をサポートしていない場合(-P)、次のシェルコマンドを使用します。

grep -w "$(printf '[0-9]%.0s' {1..4})" file

どこでprintf '[0-9]%.0s' {1..4}4回生産し[0-9]ます。この方法は、長い数字があり、パターンを繰り返したくない場合に便利です(4探している数字の数に置き換えるだけです)。

を使用-wすると、単語全体が検索されます。ただし、などの英数字の文字列に興味がある場合は、パターンの最後に1234a追加[^0-9]します。たとえば、

grep "$(printf '[0-9]%.0s' {1..4})[^0-9]" file

使用$()は基本的にコマンドの置換です。この投稿をチェックしてprintf、パターンがどのように繰り返されるかを確認してください。


0

fileシステム内の実際のファイル名に置き換えることにより、以下のコマンドを試すことができます。

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

grepコマンドのその他の用途については、このチュートリアルを確認することもできます。

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