🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

自然言語処理

自然言語処理は、日常的に使用される自然言語をコンピューターに処理させる技術やソフトウェアの総称です。

Q&A

解決済

2回答

985閲覧

正規表現の「()」および「?:」の効力について

ikegami_m

総合スコア6

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

自然言語処理

自然言語処理は、日常的に使用される自然言語をコンピューターに処理させる技術やソフトウェアの総称です。

0グッド

1クリップ

投稿2021/02/24 10:01

編集2021/02/24 10:08

pythonの自然言語処理にて、正規表現の記述方法に困っております。

#試したこと
'[[Category:イギリス|*]]'という文字列から、'イギリス'だけを抽出しようとしています。

python

1import re 2 3text = '[[Category:イギリス|*]]' 4 5pattern1 = r'.*[Category:.*?' 6pattern2 = r'.*[Category:(.*?)' 7pattern3 = r'.*[Category:(.*?)(?:\|.*)' 8 9result1 = re.findall(pattern1, text, re.MULTILINE) 10print(result1) 11result2 = re.findall(pattern2, text, re.MULTILINE) 12print(result2) 13result3 = re.findall(pattern3, text, re.MULTILINE) 14print(result3)
#結果 ['[[Category:'] [''] ['イギリス']

##質問1
「pattern1 = r'.[Category:.?'」と「pattern2 = r'.[Category:(.?)'」は、**()**を付けだだけにもかかわらず、出力結果になぜこのような差が生まれるのでしょうか。

##質問2
(?:)は、調べると「正規表現のキャプチャしない指定の記述である」とされています。
pattern3の例でいうと\|以降の文字列を検索対象とするがキャプチャしないという意味だと思うのですが、結果'イギリス'の文字列が抽出できた意味が理解できません。

##動作環境
APPLE MacBook-Pro python 3.8.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

質問1の回答

re.findall() のクセのある仕様です。re.findall()は、

  • 正規表現にキャプチャ括弧がない場合、正規表現全体にマッチした文字列のリストを返します
  • 正規表現にキャプチャ括弧が1つある場合、そのキャプチャ括弧でキャプチャした文字列のリストを返します
  • 正規表現にキャプチャ括弧が2つ以上ある場合、それらでキャプチャした文字列のタプルのリストを返します

質問2の回答

python

1pattern2 = r'.*[Category:(.*?)' 2pattern3 = r'.*[Category:(.*?)(?:\|.*)'

非キャプチャ括弧 (?:) かキャプチャ括弧かというのはこの質問中では重要ではありません。findall()の結果に入るかどうかという違いだけです。この場合 (?:\|.*)\|.* にしても結果は同じです。
問題はその前の .*? です。できるだけ短くマッチする繰り返しなので、pattern2では後続の条件がないため常に0文字にマッチ、pattern3では後続の条件により | が出現するまでマッチします。

投稿2021/02/24 10:19

編集2021/02/24 10:30
int32_t

総合スコア21679

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikegami_m

2021/02/24 11:39

とても分かりやすい解説ありがとうございます。理解できました。
guest

0

findallはグループ(括弧で囲まれた部分)が一つもなければ、パターン全体がマッチした文字列をリストにして返し、グループが一つだけならば、マッチした文字列のうちグループ部分をリストにして返し、グループが複数あれば各マッチごとのグループのタプルをリストにして返します。
また、に?をつけた?は、「0文字以上の繰り返しであり、最小の文字列」にマッチします。
つまりpattern1の末尾の.?は空文字に対応しています。
なので、.
?をグループにされているpattern2は空文字になるわけです。
一方でpattern3は(?:|.)がついていますが、?:は「この括弧はグループとして記憶しない」という意味になります。なぜそんなものがいるのかというと、括弧は単にパターンを塊で区切るのにも使うからです。(|のorとか)
そして、その部分のパターンは「|と0文字以上の任意の文字」となります。
pattern1,2では.
?は「最小の長さの任意の文字列」であり、他に制限がなかったので空文字になっていましたが、pattern3では「後ろに|がある」という条件が増えているので、この場合の「最小」は「|の手前まで」になります。
だからpattern3ではグループ部分が「イギリス」にマッチするわけです。

投稿2021/02/24 10:32

kairi003

総合スコア1332

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikegami_m

2021/02/24 11:38

ようやく理解できました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問