^(\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にマッチするようになるのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答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総合スコア1610
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/10/25 10:54
2017/10/25 13:14
2017/10/26 10:26
2017/10/26 14:56
2017/10/30 10:45 編集
2017/10/31 00:42 編集
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
が試行されて bb
や bbb
は試行されません。
投稿2017/10/30 14:32
編集2017/10/31 07:11総合スコア1610
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総合スコア1610
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/10/30 10:46
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
総合スコア97
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
元々は、行頭を意味する ^
と、行末を意味する $
で挟んでたので「完全一致」検索だったはずです。
しかし $
が無くなると行末である必要が無くなり「前方一致」に化けるわけです。
完全一致の方は、最後の ".111" に .(\d)
がマッチしても行末ではないため失敗します。
しかし前方一致の方は ".111" に .(\d)
がマッチ成功するため、後に列挙されている他の(2桁以上の)パターンが試行されることなく終わってしまいます。
投稿2017/10/31 01:00
編集2017/10/31 01:03総合スコア22
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
$の意味は最後のマッチで行が丁度終わる
という意味ですから、未マッチの文字を
行末に残すようなマッチは禁止されます。
単純な話だと思うのですが・・・
投稿2017/10/30 23:27
総合スコア56
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。