質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

90.75%

  • 正規表現

    748questions

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

正規表現 (?=.*pattern)と(?=.*?pattern)の実行結果は同じ?

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 118

chida3

score 9

パスワードのバリデーションのようなものを正規表現を使って書いていたのですが、
なぜ下記のような結果になるのかよくわからないです。

import re

argStr = '123aBcde'

print('*1*')
print(re.compile(r'.*(?=.*?[a-z])').search(argStr).group())
print(re.compile(r'.*(?=.*[a-z])').search(argStr).group())
#文字列を切り出すため、肯定先読みの表現の前に「.*」を入れています

print('*2*')
print(re.compile(r'(.*?[a-z])').search(argStr).group())
print(re.compile(r'(.*[a-z])').search(argStr).group())

期待値
*1*
123a 123(※訂正しました)
123aBcde 123aBcd(※訂正しました)
*2*
123a
123aBcde

実行
*1*
123aBcde 123aBcd(※訂正しました)   ・・・(*)
123aBcde 123aBcd(※訂正しました)
*2*
123a
123aBcde

非貪欲マッチを指定しているので、(*)でも「123a」となると思っていたのですが、
そのようになりませんでした。

(?=.*pattern)と(?=.*?pattern)の実行結果はなぜ同じになってしまうのでしょうか。
ご教示賜りたいです。

**************
すみません、期待値および実行結果に一部タイプミスがあったため、訂正いたしました。

**追記**********
本来やろうとしていたことは、下記のようなバリデーションチェックです。
・英小文字、英大文字、数字がそれぞれ1文字以上あること
・全体で8文字以上であること

これ自体は、「^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$」とすればよいことが確認できました。

ただ、上記の書き方にたどりつくまでにいくつか調べていたところ、
今回質問したように「.?*」という書き方をしているものがありました。
https://qiita.com/momotaro98/items/460c6cac14473765ec14

passw0rd という文字列であれば、pとして行頭が^(?=.*?[a-z])にマッチしていることになり、また、passw0として行頭が^(?=.*?\d)にマッチしていることになります。

上記のとおりだと、(*)の実行結果は「123」になるのでは?と思ったのが、今回の質問のきっかけです。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • a_saitoh

    2018/05/13 18:36

    本当に先読みアサーションをしたいのかどうかと、どういう意味の正規表現を書いたつもりなのか、とを追記した方が良いと思います。「先頭から、最初に英子文字が出てくる処の前の文字まで」だったら[^a-z]*で済みますし。

    キャンセル

回答 2

checkベストアンサー

0

実行

*1*
123aBcde    ・・・(*)
123aBcde
*2*
123a
123aBcde

Pythonは知りませんが、一般的な正規表現エンジンではあり得ない結果だったので、ideoneで検証したら期待通りの結果でした。

*1*
123aBcd
123aBcd
*2*
123a
123aBcde

(?=.*pattern)と(?=.*?pattern)の実行結果はなぜ同じになってしまうのでしょうか。

.*? の最短一致は空文字です。
そして、前方に最長一致があれば、そちらが優先されます。

print(re.compile(r'.*(?=.*?[a-z])').search(argStr).group())

.*? の最短一致は空文字なので、この正規表現は '.*(?=[a-z])' と同義です。
.* は最長一致なので、貪欲に消費します。

123aBcd

Re: chida3 さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/13 19:18

    コメントありがとうございます。

    ちょっとみにくいですが、検査対象の文字列の文字の前後の位置を[]で示したとして、
     [0]1[1]2[2]3[4]a[5]B[6]c[7]d[8]e[9]

    ■.*(?=.*[a-z])の場合
     (?=.*[a-z])の結果は[8]となる。冒頭の.*と合わせて、「123aBcd」。
    ■.*(?=.*?[a-z])の場合
     .*(?=[a-z])と同じ。
     .*(?=[a-z])の結果は[4]or[5]or[6]or[7]or[8]のうちから最終的に[8]が該当する。
     冒頭の.*と合わせて、「123aBcd」。

    書いていただいた内容を自分なりにかみ砕くとこうなったのですが、あっていますでしょうか?

    キャンセル

  • 2018/05/13 19:53 編集

    .*(?=.*[a-z]) ---> (?=.*[a-z])の結果は "e"
    .*(?=.*?[a-z]) ---> (?=.*?[a-z])の結果は "e"
    .*(?=.*?[a-z]) ---> 消費値は "[0]1[1]2[2]3[4]a[5]B[6]c[7]d[8]"

    キャンセル

  • 2018/05/13 19:54

    (?=pattern) は消費しません。.* は消費します。

    キャンセル

  • 2018/05/13 20:27

    ちょっと理解できた気がします。
    (?=.*[a-z]) と(?=.*?[a-z])自体の結果は同じで「e」、その直前までの分について任意の文字列(.*)を消費するから、「123aBcd」となるということですね。

    キャンセル

0

まず、(?=...)グループを形成しません ので、(?=...)とマッチしたものはグループとして取れません。そして、.group()と引数なしで呼び出すと、ヒットした全体を返すようになっています。

つまり、1の方で取ってきているのは、.*にヒットしたほうです。

正規表現に関する、Python3のリファレンス

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/13 19:23

    実行結果の当初の記載が間違っていたため、改めました。

    「(?=...)はグループを形成しません」とは(?=...)で得られるのは「位置」だからという意味でしょうか。

    キャンセル

  • 2018/05/13 20:10

    いちばん端的にいえば、そう決まっているからです(「拡張記法(注:`(?...)`のブロック)は普通新しいグループを作成しません」と、上のリファレンスにもあります)。

    キャンセル

  • 2018/05/13 20:17

    該当箇所見落としていました。ありがとうございます。

    キャンセル

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

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • 正規表現

    748questions

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