re.findall( '(ab | cd)'、string)とre.findall( '(ab | cd)+'、string)


18

Pythonの正規表現で、この特異な問題に遭遇しました。re.findall('(ab|cd)', string)との違いについて教えてくださいre.findall('(ab|cd)+', string)

import re

string = 'abcdla'
result = re.findall('(ab|cd)', string)
result2 = re.findall('(ab|cd)+', string)
print(result)
print(result2)

実際の出力は次のとおりです。

['ab', 'cd']
['cd']

2番目の結果にも含ま'ab'れていないのはなぜですか。


re.findall( '(AB | CD)'、文字列)[ 'AB'、 'CD'] re.findall( '(AB | CD)+'、文字列)を取得します取得[ 'CD']

回答:


15

+1回以上一致する繰り返し数量詞です。正規表現では(ab|cd)+、+を使用してキャプチャグループ (ab|cd)繰り返します。これは最後の反復のみをキャプチャします。

この動作は、次のように推論できます。

文字列がでabcdla、正規表現がだとし(ab|cd)+ます。Regexエンジンは、位置0と1の間のグループの一致を見つけab、キャプチャグループを終了します。次に、+量指定子が表示されるため、グループを再度キャプチャしようとしcd、位置2と3の間をキャプチャします。


すべての反復をキャプチャする場合は代わりに((ab|cd)+)which とを使用して、繰り返しグループキャプチャする必要がabcdありcdます。私たちが持つ内部グループの試合を気にしないよう、あなたは、内側のグループ非キャプチャすることができます((?:ab|cd)+)一致abcd

https://www.regular-expressions.info/captureall.html

ドキュメントから

!abc!またはのようなタグに一致させたいとしましょう!123!。これら2つだけが可能であり、をキャプチャしabcたり123、取得したタグを把握したりします。それは十分に簡単です:!(abc|123)!トリックを行います。

今度は、タグは、複数の配列を含むことができることをしましょうabc123、似!abc123!たり!123abcabc!。迅速かつ簡単なソリューションは !(abc|123)+!です。この正規表現は実際にこれらのタグに一致します。ただし、タグのラベルをキャプチャグループにキャプチャするという要件を満たしていません。この正規表現が一致する!abc123!と、キャプチャグループは保存のみを行い123ます。一致する場合は!123abcabc!、格納のみabcです。


+は最後の反復のみをキャプチャするという事実を明確にするいくつかのドキュメントにリンクできますか?キャプチャグループとは何ですか?
Gulzar

1
@Gulzar、回答を更新しました。キャプチャグループについては、こちらをご覧ください-regular-expressions.info/refcapture.html
V

@Shashank、ありがとう、あなたの返信はまさに私が必要とするものです。心からの感謝
ロック

@rock質問が解決したら回答を受け入れてください。
Shashank V

括弧で正規表現全体を囲む必要はありません。ただ、'(?:ab|cd)+'動作します。
1

5

これでさらに問題が解決するかどうかはわかりませんが、簡単にフードの下で何が起こるか想像してみましょう。マッチを使用して何が起こるかを要約します。

   # group(0) return the matched string the captured groups are returned in groups or you can access them
   # using group(1), group(2).......  in your case there is only one group, one group will capture only 
   # one part so when you do this
   string = 'abcdla'
   print(re.match('(ab|cd)', string).group(0))  # only 'ab' is matched and the group will capture 'ab'
   print(re.match('(ab|cd)+', string).group(0)) # this will match 'abcd'  the group will capture only this part 'cd' the last iteration

findall文字列を一致させて同時に消費するこのREGEXで何が起こるか想像してみましょう'(ab|cd)'

      'abcdabla' ---> 1:   match: 'ab' |  capture : ab  | left to process:  'cdabla'
      'cdabla'   ---> 2:   match: 'cd' |  capture : cd  | left to process:  'abla'
      'abla'     ---> 3:   match: 'ab' |  capture : ab  | left to process:  'la'
      'la'       ---> 4:   match: '' |  capture : None  | left to process:  ''

      --- final : result captured ['ab', 'cd', 'ab']  

今と同じこと '(ab|cd)+'

      'abcdabla' ---> 1:   match: 'abcdab' |  capture : 'ab'  | left to process:  'la'
      'la'       ---> 2:   match: '' |  capture : None  | left to process:  ''
      ---> final result :   ['ab']  

これで問題が少し解消されるといいのですが。


0

だから、私にとって混乱した部分は、

パターンに1つ以上のグループが存在する場合は、グループのリストを返します。

docs

完全一致ではなく、キャプチャの一致のみが返されます。このグループをキャプチャしないようにすると(re.findall('(?:ab|cd)+', string)["abcd"]最初に期待したとおりに戻ります


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