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

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

新規登録して質問してみよう
ただいま回答率
85.48%
正規表現

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

Q&A

解決済

7回答

2411閲覧

何故、マッチしなくなるのか

aaaaaaaa

総合スコア501

正規表現

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

1グッド

4クリップ

投稿2017/10/25 10:28

^(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])$は、ipアドレスにマッチする正規表現です。
この正規表現から^$を抜くと、四つある選択のうち最後の選択(ドル記号と隣接する選択)の動作に疑問を憶えました。^$が存在するなら「111.111.111.111」は、マッチしますが、無しなら「111.111.111.111」は、マッチせず「111.111.111.1」となります。
最後の選択の後ろに何かがあることで、例えば先述ならドル記号、何なら.でもいいですが(その場合、文字列は111.111.111.111.にしないといけないが)、最後の選択が残り二つの11を考慮しているのでは、と思ったのです。

なぜ、^$がなくなると、最後の選択は、~.111ではなく~.1にマッチするようになるのでしょうか。

oriduru👍を押しています

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2017/10/30 23:28 編集

ミスはあるかもしれないが (1?¥d?¥d|2[0-4]¥d|25[0-5])でもいいような
guest

回答7

0

(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])
は左から試行され 1 とマッチして終了するからです。
(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])$
の場合はこのグループが行末と接している必要があるので 1 がマッチしなくなります。

ほとんどの正規表現エンジンでは最も左のパターンから試行されるので
([01]\d\d|2[0-4]\d|25[0-5]|\d\d|\d)
のように桁数が長い方から並べると良いです。

投稿2017/10/25 10:39

編集2017/10/25 13:14
chitoku

総合スコア1610

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

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

退会済みユーザー

退会済みユーザー

2017/10/25 10:54

最短でマッチするからではなく、chitoku さん自身が書いている通り、左のパターンから試行されるからでは?
chitoku

2017/10/25 13:14

確かに最初と最後で言っていることがよくわからないので直しました。
aaaaaaaa

2017/10/26 10:26

ご回答ありがとうございました。 選択の後ろに何かしらの記号、今回でいえばキャレットとともに配置されているドル記号があるから1が選ばれないということですが、それはなぜなのでしょうか。 ドル記号と接することによって、選択の早い者勝ちという機能がなくなった、というか違う動きになった理由はなんなのでしょうか。
chitoku

2017/10/26 14:56

abc\d$ という正規表現を考えてみてください。 "abc1" という文字列にはマッチしますが "abc1a" という文字列にはマッチしません。 選択は関係ありません。
aaaaaaaa

2017/10/30 10:45 編集

ご返答ありがとうございます。 申し訳ありません。返答文の中にある正規表現とその動きは理解できますが、それと質問の中の正規表現が繋がらずよく理解できません。 返答文中の「abc\d$」は、文末がabc\d(0~9の何れか)になっているものだけがマッチする正規表現だと思いますが、「(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])$」は、一桁の数字か、二桁の数字か、上一桁目が0か1の三桁の数字か、上一桁目が2で上二桁目が0から4の何れかの三桁の数字か、上一桁目が2、上二桁目が5、上三桁目が0から5の三桁の数字のどれかと、そのあとに文末が来るものに該当する必要があります。「111.111.111.111」のうち「111.111.111.」まではマッチ済みで最後の「111」に該当するのは、上記の選択のうち「上一桁目が0か1の三桁の数字」が該当します。 しかしドル記号が無いと先述の「上一桁目が0か1の三桁の数字」が該当しなくなります。「111」のうち「1」がマッチするということは、上記の選択のうち「文末が一桁の数字」が該当したと思うのですが、なぜドル記号がなくなったことで、「111」がマッチする「上一桁目が0か1の三桁の数字」から「1」がマッチする「文末が一桁の数字」がマッチするようになったのでしょうか。 選択とは、関係ないとのことですが、いまいちよくわかりません。
AllInBalance

2017/10/31 00:42 編集

ドル記号がなくなったことで、文末じゃなくて良くなったからではないですか? 「文末」という条件が無くなることで 1. 一桁の数字 2. 二桁の数字 3. 上一桁目が0か1の三桁の数字 4. 上一桁目が2で上二桁目が0から4の何れかの三桁の数字 5. 上一桁目が2、上二桁目が5、上三桁目が0から5の三桁の数字 の順にマッチ判定するので、 111.111.111.111 もマッチするけれど、 111.111.111.1 の方が先にマッチすると。
guest

0

ベストアンサー

逆にドル記号があったときに「111」がマッチする理由として行末を意味するドル記号が存在しているから「1」がマッチしなくなるというのが中々理解することができません。ドル記号がなかった時と同様に左から順に選択が試行されないのは、なぜなのでしょうか。

選択は左から順に試行されています。\d$ 単独の場合は 1 にマッチしますが、これはそれ以前のパターンに連続している必要があるからです。

たとえば正規表現 a\d$a1 はマッチしますが ab1 にはマッチしません。\d$a に続いていないからです。

選択の後にドル記号が来ますので、記号にすると「\d$、\dd$、[01]\d\d$、2[0-4]\d$、25[0-5]$」の何れかが選ばれるはずです。

連続する必要があるので、「『\d$、\dd$、[01]\d\d$、2[0-4]\d$、25[0-5]$』の何れかが、直前までのパターンに接しているもの」を左から試行することになります。

\d$1 が行末と接しているのでこれ単体では確かにマッチしますが、直前までのパターンと接しているという条件に当てはまらないわけです。111 は直前と接しており、かつ行末とも接するのでここで終了します。

逆に a.*(b|bb|bbb)$ のように直前に制約がなければ .*b の直前にある任意のゼロ文字以上にマッチし続けるので直前に何がきていようと常に一番左の b が試行されて bbbbb は試行されません。

投稿2017/10/30 14:32

編集2017/10/31 07:11
chitoku

総合スコア1610

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

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

退会済みユーザー

退会済みユーザー

2017/10/30 23:26

任意のゼロ文字以上だろうに .*
aaaaaaaa

2017/10/31 02:58

ご回答ありがとうございました。ここまで付き合っていただいて本当に感謝しております。
chitoku

2017/10/31 07:11

@asahina1979 そうですね、修正しました
guest

0

なるほど。
おそらく私は質問者さんと同じ誤解をしており、大変ためになりました。
^と$はそれぞれ行頭と行末を意味していたんですね。
正規表現の始まりと終わりを意味するもので、行中でもマッチするものかと思っていました。

例えば、^abc$は、aabccという文字列のabcにもマッチするものかと思っていました。

よくよく考えると、これだと^と$はついていてもいなくても変わらない、無意味な記号になってしまいますね(^_^;)

投稿2017/10/30 23:51

020n

総合スコア36

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

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

0

「(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])$」は、文末が一桁の数字か、二桁の数字か、上一桁目が0か1の三桁の数字か、上一桁目が2で上二桁目が0から4の何れかの三桁の数字か、上一桁目が2、上二桁目が5、上三桁目が0から5の三桁の数字のどれかに該当する必要があります。「111.111.111.111」のうち「111.111.111.」まではマッチ済みで最後の「111」に該当するのは、上記の選択のうち「上一桁目が0か1の三桁の数字」が該当します。

その通りです。

厳密には「一桁の数字か、二桁の数字か、上一桁目が0か1の三桁の数字か、上一桁目が2で上二桁目が0から4の何れかの三桁の数字か、上一桁目が2、上二桁目が5、上三桁目が0から5の三桁の数字のどれか」のあとに文末が続くと読みます。

「111」のうち「1」がマッチするということは、上記の選択のうち「文末が一桁の数字」が該当したと思うのですが、なぜドル記号がなくなったことで、「111」がマッチする「上一桁目が0か1の三桁の数字」から「1」がマッチする「文末が一桁の数字」がマッチするようになったのでしょうか。

$ 記号がない場合の話ですよね? だとすれば「文末が一桁の数字」という条件ではなく、「一桁の数字」という意味になります。したがって 1 が一桁の数字にマッチするため、選択のそれより右にあるパターンは試行されていません。

投稿2017/10/27 13:22

編集2017/10/27 13:24
chitoku

総合スコア1610

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

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

aaaaaaaa

2017/10/30 10:46

再び回答してくださってありがとうございます。とtも助かります。 >>厳密には<中略>文末が続くと読みます。 おっしゃる通りでした。ご指摘ありがとうございます。先の返答を編集しました。 >>$ 記号がない場合<中略>選択のそれより右にあるパターンは試行されていません。 ドル記号なしだと 「111.111.111.111」の「111」のうち「1」が正規表現の選択の一桁の数字に該当し、 $ありだと「111.111.111.111」のうち「111」が正規表現の上一桁目が0か1の三桁の数字に該当します。 このような動き(ドル記号がなくなったことによって.111のうち.1しかマッチしなくなった)に疑問を憶え、その疑問の返答として " (\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]) は左から試行され 1 とマッチして終了するからです。 (\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])$ の場合はこのグループが行末と接している必要があるので 1 がマッチしなくなります。 " とありました。選択が左から順に試行されていくので、1がマッチすることはおかげさまで理解することができましたが、逆にドル記号があったときに「111」がマッチする理由として行末を意味するドル記号が存在しているから「1」がマッチしなくなるというのが中々理解することができません。ドル記号がなかった時と同様に左から順に選択が試行されないのは、なぜなのでしょうか。 選択の後にドル記号が来ますので、記号にすると「\d$、\dd$、[01]\d\d$、2[0-4]\d$、25[0-5]$」の何れかが選ばれるはずです。 そして先述の通り左から順に試行されていくので「\d$」が1をマッチして文末にいって処理終了となりそうですが、「[01]\d\d$」が選ばれます。なのでドル記号があると「1」でなく「111」がマッチします。 なぜ、ドル記号があると111にマッチするのでしょうか。 重ね重ね申し訳ありませんが、よろしくお願いいたします。
guest

0

$が文字列の終端または行末を意味するので、それを持つものに限定します。

$ を取り除くと、 対象文字列が 123.123.123.123.123.123 だったり、
123.123.123.12345789 のような、IPアドレスとしてはおかしな文字列にも
マッチしてしまいますが問題ないでしょうか。
複数行オプションが設定されていれば
aaa\n123.123.123.123 のような文字列にもマッチする可能性があります。
123.123.123.123\n に対してマッチした場合にどうなるかも考える余地があります。

正規表現はその表現から正確に意図を汲み取ることが難しく、
単体で扱うと事故を起こすことが多々あるので、関数化した上で
思いつく限りとにかく多量のテストケースを書いてぶつける事をお勧めします。

投稿2017/10/31 02:17

TakeoSaki

総合スコア97

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

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

0

元々は、行頭を意味する ^ と、行末を意味する $ で挟んでたので「完全一致」検索だったはずです。
しかし $ が無くなると行末である必要が無くなり「前方一致」に化けるわけです。

完全一致の方は、最後の ".111" に .(\d) がマッチしても行末ではないため失敗します。
しかし前方一致の方は ".111" に .(\d) がマッチ成功するため、後に列挙されている他の(2桁以上の)パターンが試行されることなく終わってしまいます。

投稿2017/10/31 01:00

編集2017/10/31 01:03
Pc_Felith

総合スコア22

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

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

0

$の意味は最後のマッチで行が丁度終わる
という意味ですから、未マッチの文字を
行末に残すようなマッチは禁止されます。

単純な話だと思うのですが・・・

投稿2017/10/30 23:27

tknakamuri

総合スコア56

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問