web-dev-qa-db-ja.com

貪欲でない文字列正規表現マッチング

ここで明らかな何かが欠けていることは間違いありませんが、Rに貪欲でない正規表現を使用させることはできません。

> library(stringr)
> str_match('xxx aaaab yyy', "a.*?b")                                         
     [,1]   
[1,] "aaaab"

基本関数は同じように動作します。

> regexpr('a.*?b', 'xxx aaaab yyy')
[1] 5
attr(,"match.length")
[1] 5
attr(,"useBytes")
[1] TRUE

http://stat.ethz.ch/R-manual/R-devel/library/base/html/regex)の「greedy」コメントによると、一致はabだけになると思います。 .html

デフォルトでは、繰り返しは貪欲であるため、可能な最大の繰り返し数が使用されます。これは、?を追加することで「最小」に変更できます。数量詞に。 (近似マッチングを可能にする数量詞がさらにあります。TREのドキュメントを参照してください。)

誰かが私に何が起こっているのか説明してもらえますか?

更新。クレイジーなのは、他のいくつかのケースでは、貪欲でないパターンが期待どおりに動作することです。

> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*>')
     [,1]                                          
[1,] "<a href=\"abc\">link</a> yyy <h1>Header</h1>"
> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*?>')
     [,1]              
[1,] "<a href=\"abc\">"
23
Victor K.

コンセプトが難しいので頑張ります…少しわかりにくい方は、気軽に編集して説明してください。

パターンに一致する式が左から右に検索されます。はい、次の文字列aaaabaaabaab、およびabはすべてパターンに一致しますが、aaaabは一番左から始まるものが返されます。

したがって、ここでは、貪欲でないパターンはあまり役に立ちません。たぶん、この他の例は、欲張りでないパターンが始まるときにあなたがよりよく理解するのを助けるでしょう:

str_match('xxx aaaab yyy', "a.*?y") 
#      [,1]     
# [1,] "aaaab y"

ここではすべての文字列aaaab yaaaab yyaaaab yyyパターンに一致し、同じ位置から開始しましたが、貪欲でないパターンのため、最初のパターンが返されました。


では、最後のabをキャッチするために何ができるでしょうか。これを使って:

str_match('xxx aaaab yyy', ".*(a.*b)")
#      [,1]        [,2]
# [1,] "xxx aaaab" "ab"

それはどのように機能しますか?貪欲なパターンを追加することによって.*前面では、キャプチャされたグループに最後の可能なaを配置するようにプロセスに強制しています。

24
flodel

問題2つの文字列間の最短ウィンドウの一致です。 @flodelは、正規表現エンジンが文字列を左から右に解析していることを正しく記述しているため、すべての一致はleftmostです。貪欲と怠惰は右側の境界にのみ適用されます。貪欲な数量詞は右端の境界まで部分文字列を取得し、怠惰な数量詞は後続のサブパターンの最初の出現に一致します。

の例を参照してください:

_> library(stringr)
> str_extract('xxx aaaab yyy', "a[^ab]*b")
[1] "ab"
> str_extract('xxx aaa xxx aaa zzz', "xxx.*?zzz")
[1] "xxx aaa xxx aaa zzz"
> str_extract('xxx aaa xxx aaa zzz', "xxx(?:(?!xxx|zzz).)*zzz")
[1] "xxx aaa zzz"
_

最初と3番目のシナリオは最短のウィンドウを返し、2番目のシナリオは現在の問題を示していますが、複数文字の入力があります。

シナリオ1.境界は1文字です

abが単一文字の場合、最も短いウィンドウは否定された文字クラスを使用して検索されます。 _a[^ab]*b_は、asとbsを間に挟まずに、aから次のbまでの部分文字列を簡単に取得します。

シナリオ2.境界は単一文字ではありません

これらの場合、さらに展開できる 強化された貪欲なトークン を使用できます。 xxx(?:(?!xxx|zzz).)*zzzパターンはxxxと一致し、xxxまたはzzz文字シーケンスの開始文字ではない改行文字以外の0以上の文字(_(?!xxx|zzz)_は負の先読みであり、すぐ右側の部分文字列が先読みパターンと一致する場合、一致に失敗します)、次にzzz

これらのmatchingシナリオは、ベースR regmatchesで簡単に使用できます(先読みをサポートするPCRE正規表現フレーバーを使用)。

_> x <- 'xxx aaa xxx aaa zzz xxx bbb xxx ccc zzz'
> unlist(regmatches(x, gregexpr("xxx(?:(?!xxx|zzz).)*zzz", x, Perl = TRUE)))
[1] "xxx aaa zzz" "xxx ccc zzz"
_

注:ベースRでPCRE正規表現を使用する場合、または_str_extract_/_str_match_でICU正規表現)を使用する場合、_._は改行文字と一致しません。この動作を有効にするには、パターンの開始時に_(?s)_を追加する必要があります(インラインDOTALL修飾子)。

6