質問

質問

私は答えたスーパーユーザーに関する質問これは、grep出力に使用される正規表現に関連しています。

私が答えた答えはこんな感じです。

 tail -f log | grep "some_string.*some_string"

それから私の答えに対する3つの意見で@シングル次のように書きました:

.*欲を唱えれば、あなたが望むよりも多くを捕まえることができます。.*?一般的には良いです。

だからこれ、

これは基本的な欲望の代わりに怠惰なものにする?修飾子です。*PCREを想定します。

検索しましたが、PCRE私の答えでこれが何を意味するのか理解できませんか?

この最後のもの、

また、これはシェルglobではなく正規表現(grepはデフォルトでPOSIX正規表現を実行する)であることを指摘する必要があります。

私は正規表現が何であるかとgrepコマンドでの基本的な使い方だけを知っています。だから私はこれら3つの意見のどれも受け取ることができず、次のような質問が心の中にあります。

  • 使用上の違いは何ですか?.*?そして.*
  • どんな状況でどちらが良いですか?例えばください。

誰かがこのコメントを理解できれば役に立ちます。


アップデート:質問への回答正規表現はShell Globsとどう違うのですか? @クサラナンダもしこのリンク彼のコメントで。

注:必要に応じてお読みください。この質問に対する私の答え答える前にコンテキストを参照してください。

答え1

次のような文字列を使用しているとします。

can cats eat plants?

貪欲演算子を使用c.*sすると、でc始まり終わる文字列全体と一致しますs。貪欲演算子は、sが最後に表示されるまで一致し続けます。

怠惰を使用すると、文字列が最初に表示されるc.*?sまでのみ一致します。scan cats

上記の例では、次のような結論を下すことができます。

「Greedy」は、可能な限り長い文字列と一致することを意味します。 「Lazy」は、できるだけ短い文字列と一致することを意味します。?数量子(たとえば*+または?)にaを追加すると、{n,m}数量子が無効になります。

答え2

Ashokが指摘した。.*だから、.*?いくつかの追加情報を提供します。

grep(GNUバージョンと仮定)4つの文字列一致方法をサポートしています。

  • -Fオプション付きの固定文字列
  • デフォルト正規表現(BRE)、デフォルト
  • -Eオプション付き拡張正規表現(ERE)
  • -PGNU grepのオプションを持つPerl互換正規表現(PCRE)

grepデフォルトでは BRE が使用されます。

BRE と ERE は次のように記録されます。一般的な表現POSIX および PCRE の章は、次の文書で文書化されています。公式ウェブサイト。機能と構文は実装ごとに異なる場合があります。

BREもEREもサポートしていないことは言及する価値があります。怠惰:

複数の隣接する反復記号(「+」​​、「*」、「?」、および空白)の動作は、未定義の結果を生成します。

したがって、その機能を使用するにはPCREを使用する必要があります。

# PCRE greedy
$ grep -P -o 'c.*s' <<< 'can cats eat plants?'
can cats eat plants

# PCRE lazy
$ grep -P -o 'c.*?s' <<< 'can cats eat plants?'
can cats

説明してもらえますか?.*そして.*?

  • .*可能な「最も長い」1パターンを一致させるために使用されます。

  • .*?可能な「最も短い」1パターンを一致させるために使用されます。

私の経験の中で最も望ましい行動は通常2番目の行動です。

たとえば、次の文字列があり、その間の内容ではなく、htmlタグ2のみを一致させようとしているとします。

<title>My webpage title</title>

.*比較してみてください.*?

# Greedy
$ grep -P -o '<.*>' <<< '<title>My webpage title</title>'
<title>My webpage title</title>

# Lazy
$ grep -P -o '<.*?>' <<< '<title>My webpage title</title>'
<title>
</title>

1.正規表現の文脈では、「最も長い」と「最も短い」の意味は少し難しいです。クサロナンダが指摘したように。詳しくは公式ドキュメントをご覧ください。
2.HTMLを解析するために正規表現を使用することはお勧めできません。。これは教育目的でのみ使用される例なので、本番では使用しないでください。

答え3

文字列はさまざまな方法で一致させることができます(単純なものからより複雑なものまで):

  1. 静的文字列(var = 'Hello World!'と仮定):

    [ "$var" = "Hello World!" ] && echo yes
    echo "$var" | grep -F "Hello"
    grep -F "Hello" <<<"$var"

  2. 具体的に:

    echo ./* #listみんなpwdのファイル。
    case $var in (*Worl*) echo yes;; (*) echo no;; esac
    [[ "$var" == *"Worl"* ]] && echo yes

    基本と拡張グローブがあります。このcase例では、デフォルトのglobを使用しています。 bash[[の例では、拡張globを使用しています。最初のファイルの一致は、デフォルトでもextglobbash の設定など、一部のシェルの拡張であってもかまいません。この場合、両方とも同じです。 Grepはグローブを使用できません。

    スター全体的な状況アスタリスクとは異なる意味正規表現:

    * matches any number (including none) ofすべての文字
    * matches any number (including none) of the前の要素

  3. 基本正規表現(BRE):

    echo "$var" | sed 's/W.*d//' #印刷:こんにちは!
    grep -o 'W.*d' <<<"$var" #世界を印刷する!

    (デフォルト) シェルまたは awk には BRE はありません。

  4. 拡張正規表現(ERE):

    [[ "$var" =~ (H.*l) ]] #コンテスト:Hello World
    echo "$var" | sed -E 's/(d|o)//g' #print:地獄が轟音する!
    awk '/W.*d/{print $1}' <<<"$var" #印刷:こんにちは
    grep -oE 'H.*l' <<<"$var" #印刷:こんにちは、世界

  5. Perl互換正規表現:

    grep -oP 'H.*?l #印刷:ハル

PCREでのみaには*?特定の文法的意味があります。
アスタリスクを怠惰にします(貪欲ではありません)。欲を怠惰に変える

$ grep -oP 'e.*l' <<<"$var"
ello Worl

$ grep -oP 'e.*?l' <<<"$var"
el

これは氷山の一角に過ぎません。欲、怠惰流順または所有欲が強い。しかも前を見て後ろを振り返るただし、これはアスタリスクには適用されません*

貪欲ではない正規表現と同じ効果を得る代替手段があります。

$ grep -o 'e[^o]*o' <<<"$var"
ello

アイデアはとても簡単です。 dotを使用しないで、.一致する次の文字を無効にしてください[^o]。ネットワークタグの使用:

$ grep -o '<[^>]*>' <<<'<script type="text/javascript">document.write(5 + 6);</script>'
<script type="text/javascript">
</script>

上記は@Bob 3のすべてのコメントを完全に明確にします。定義:

  • .*はglobではなく一般的な正規表現です。
  • 正規表現のみがPCREと互換性があります。
  • PCREから: ?Modify*の量子。.*それは貪欲ではありません.*?

質問

  • 使い方の違いは何ですか??そして。

    • A は.*?PCRE 構文でのみ有効です。
    • Aは.*携帯性が良いです。
    • ポイントを負の文字範囲に変更すると、貪欲ではない一致と同じ効果が得られます。[^a]*
  • どんな状況でどちらが良いですか?例えばください。
    より良いですか?目標によって異なります。良いことはなく、それぞれ異なる目的を持っています。上記の例をいくつか紹介しました。もっと必要ですか?

関連情報