webdevqa.jp.net

grepで貪欲でない一致を行う方法は?

最短一致をgrepしたいのですが、パターンは次のようになります。

<car ... model=BMW ...>
...
...
...
</car>

...は任意の文字を意味し、入力は複数行です。

159
syker

欲張りでない(または怠laな)マッチを探しています。正規表現で貪欲でない一致を取得するには、数量詞の後に修飾子?を使用する必要があります。たとえば、.*.*?に変更できます。

デフォルトでは、grepは貪欲でない修飾子をサポートしていませんが、grep -Pを使用してPerl構文を使用できます。

249
Mark Byers

実際、.*?Perlでのみ機能します。同等のgrep拡張正規表現構文がどうなるかはわかりません。幸いなことに、grepでPerl構文を使用できるので、grep -Pは機能しますが、egrepと同じgrep -Eは機能しません(貪欲になります)。

参照: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html

80
John Smith

grep

grepの貪欲でない一致には、否定文字クラスを使用できます。言い換えれば、ワイルドカードを避けるようにしてください。

たとえば、ページコンテンツからjpegファイルへのすべてのリンクを取得するには、次を使用します。

grep -o '"[^" ]\+.jpg"'

複数行に対処するには、最初にxargsを介して入力をパイプ処理します。パフォーマンスのために、 ripgrep を使用します。

10
kenorb

このスレッドで何かを試した後に動作する私のgrep:

echo "hi how are you " | grep -shoP ".*? "

必ず各行にスペースを追加してください

(私は単語を吐き出すための行ごとの検索でした)

9
jonz

簡単な答えは、次の正規表現を使用することです。

(?s)<car .*? model=BMW .*?>.*?</car>
  • (?s)-これは複数行にわたって一致します
  • 。*? -任意の文字に、怠matchesな方法で何度も一致します(最小一致)

(少し)より複雑な答えは:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

これにより、次のテキストでcar1とcar2を一致させることができます。

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..)キャプチャグループを表します
  • このコンテキストの\ 1は、グループ番号1をキャプチャして最後に一致したものと同じテキストと一致します
0
jmc