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

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

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

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

正規表現

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

Q&A

解決済

4回答

1819閲覧

IPアドレスの正規表現、orを使ったときのマッチ順序

willii

総合スコア12

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

正規表現

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

0グッド

1クリップ

投稿2018/09/10 21:03

前提・実現したいこと

オンラインの無料学習サイトで正規表現を学習しました
そこで最近、teratailで質問文にある質問を解いて、BAと答えあわせをして遊んでいます
その中で「こちら」の質問を解いていた際の疑問です

質問、回答に書かれている正規表現の動作確認は
Online regex tester and debugger: PHP, PCRE, Python, Golang and JavaScript
で行っています

発生している問題・エラーメッセージ

上記リンク先の質問でBAとなっている回答には、このように書いてありました

(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])

は左から試行され 1 とマッチして終了するからです。

そこで、まずこの正規表現の行末側の動作を試してみました
すると、括弧内に書かれている\dにマッチした直後に、括弧内のORを抜けるような、動作をしています

よって「マッチした文字があった場合は、すぐにカッコ内のその他OR条件を無視してカッコを抜ける」という結論を出しました
後続のOR条件に書かれており、成立するはずの.(\d\d).([01]\d\d)が無視されていることからも、この結論は、正しいと思っていました

次に、この状態で先頭の条件の動作を見てみました

(\d).が成立するため、その時点でカッコ内のほかの条件を無視しカッコを抜ける」と思っていたのですが、そうではなく、成立する条件の後ろに書かれた|([01]\d\d).にマッチし、カッコ内を抜けていました

これはおかしくないのでしょうか?
(\d).は確かに成立するはずです
なのに、なぜそれを無視して最後にマッチする条件を見たのでしょうか?

何か見落としている所があれば教えて頂きたいです
よろしくお願いします

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2018/09/10 22:44

単語としてマッチさせないから(AA1.123.123.123 )でもマッチしそうだな
think49

2018/09/10 23:22

「数値の途中でマッチしてしまう問題」もありますね。年月日に /\d\.|\.\d/ が付くだけで成立します。"2018.09.11.08.15"
guest

回答4

0

ベストアンサー

REGULAR EXPRESSION v1

(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).

TEST STRING

111.111.111.111

正規表現エンジンに依ると思いますが、一般に正規表現は文字列を前方から検索します。
そして、マッチした文字列の次の文字(厳密には文字と文字の境界)から検索を再開します。

  1. "111." に [01]\d\d. がマッチ
  2. 2つ目の "111." から検索を再開する

"111." は既に消費されているので、"1." にマッチする事は出来ません。

Re: willii さん

投稿2018/09/10 23:10

編集2018/09/11 00:17
think49

総合スコア18164

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

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

willii

2018/09/11 04:30 編集

>正規表現エンジンに依ると思いますが、... >..."111." は既に消費されているので、"1." にマッチする事は出来ません。 >`(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).` 頂いた回答は「上に引用した正規表現は`111.111.111.111`の一番先頭の`111.`にマッチするため、2つ目以降の`111.`にはマッチしない」という理解で合っていますか? そうであれば、上に引用した正規表現を[このように](https://regex101.com/r/RtFfFg/1)四つ繰り返して書けば、`111.111.111.111`にマッチする正規表現ができるのではないかと思います しかし実際は、最後の`111`の部分は`[01]\d\d`がマッチせず、`\d`がマッチしているようです https://regex101.com/r/RtFfFg/1 これは`(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).`でOR条件の中の三番目に書かれている`[01]\d\d`にマッチするという結果と検索の方法(?)が違うように見えるのですが、どういった仕組みなのでしょうか? という質問をしたつもりでした 少し質問の文を推敲することにします 回答を読み違えていたら是非教えて頂きたいです よろしくお願いします
think49

2018/09/11 10:23 編集

私は質問内容を「/(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5])./.exec('111.111.111.111') を実行すると、なぜ、([01]\d\d)\ にマッチするのですか。左側から評価されるのですから、\d. が先にマッチすると思うのですが。」と解釈しました。 > https://regex101.com/r/RtFfFg/1 その正規表現は初めてみました。 私としては、質問内容が変わっているように感じられます。 正規表現パターンは左から評価されるので、.\dにマッチしますね。 検索開始位置が一文字ずつズレるイメージが出来ていないのだと思いますので、当初の質問に戻ってよく考えてみてください。 文字列先頭から検索した場合、\d.にマッチせず、\d\d.にマッチせず、[01]\d\d. にマッチします。
willii

2018/09/11 22:58

>私は質問内容を...と解釈しました。 私がこの質問で書いていることもそのような内容になっています どうやら、私が回答文をしっかりと、読めていないようです >その正規表現は初めてみました。 この正規表現は[発生している問題・エラーメッセージ]に書いた正規表現を組み合わせたもので、質問文に書かれていることが全てになっています 質問に説明が足りなくて申し訳ありません >文字列先頭から検索した場合...[01]\d\d. にマッチします。 ようやく理解できました 「文字列の一文字目からマッチする正規表現をまず検索して、マッチするものがあったら終了、なければ2文字目から検索する」という動作をするから、このような結果になる、ということですね >...文字列を前方から検索します というふうに回答にも書かれていたのに、全く気づきませんでした 詳しく説明くださりありがとうございました
guest

0

正規表現側から見るのではなく、検索対象文字列側から見るべきではないでしょうか?

まず先頭文字の1がマッチするかどうかを調べ、次に2文字目の1を調べる。
そうすると、最初の条件では2文字目でNG、2つ目の条件では3文字目でNGになります。
で、3つ目の条件で4文字マッチしたと言うことだと思います。

検索対象の長さはどれくらいか分からないので、カッコ内の条件を調べるために複数回検索対象をサーチするのは非効率かと思います。

最長一致と言うのは、複数の条件の内最も答えが長いものと言う意味ではなく、最初にマッチした条件で成立する最も長い文字列と言うことだと思います。

投稿2018/09/11 09:45

chun

総合スコア324

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

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

willii

2018/09/11 23:14

>まず先頭文字の1が... >...3つ目の条件で4文字マッチしたと言うことだと思います。 先頭文字からマッチする正規表現を探すのですね 正規表現がどのように文字列を検索しているのか、理解できました >最長一致と言うのは、...と言うことだと思います。 最長一致は条件の中でもっとも長くマッチする正規表現を選択する、ようなものではないんですね 非常に参考になりました ご回答して頂きありがとうございました
guest

0

think49さんの回答の補足です。

まず正規表現全体の1文字目からが、対象文字列の1文字目からにマッチするかチェックします。マッチすれば終わり。
マッチしない場合は、今度は、正規表現全体の1文字目からが、対象文字列の2文字目からにマッチするかチェックします。
以下同様に、対象文字列のチェック開始位置をずらしながらチェックします。
(もちろん、^が正規表現の先頭に付いていたらずらしませんが)

あと、高度な指定で、マッチが失敗したときの動作を変更する事も出来ます。

先頭に^が付いておらず末尾に$が付いているケースでも、対象文字列の後ろからチェックすると言う事はありません。
同様に今回は.が正規表現末尾に付いていますが、それを先にマッチさせて、前方に遡ってチェックするような事は行いません。あくまで先頭からチェックです。

##追記

(\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.にマッチするか?(中略)25[0-5].にマッチするか?の順に調べ、どれもマッチしなければ、

文字列の2文字からが、以下同様。
文字列の3文字目からが、以下同様。
以下同様。

となります。
対象文字列が111.111.111.111の場合、「文字列の先頭文字からが、[01]\d\d.にマッチする」のが最初なので、それが採用されます。

投稿2018/09/11 01:01

編集2018/09/11 05:40
otn

総合スコア84555

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

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

willii

2018/09/11 04:44 編集

>まず正規表現全体の1文字目からが、...マッチすれば終わり。 他の方の回答を読むところ「カッコの中に書いたOR条件をそれぞれで実行していって、一番長い文字列にマッチしたものを結果として返す」ような動作をしているのだと思っていたのですが、これは間違った理解だったでしょうか? もし「マッチした時点で終了」するならば、`(\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]).`という正規表現で`111.`を検索すると、[このように](https://regex101.com/r/krML98/1)一番最初に`(\d).`がマッチし、そこでOR条件を終了するため、`1.`が結果となるのではないでしょうか? 間違ったところがあれば是非教えて頂きたいです よろしくお願いします
willii

2018/09/11 23:16 編集

追記をして頂きありがとうございます >文字列の先頭文字からが、...の順に調べ 「文字列の先頭文字からマッチする正規表現を探し、あればそこで終了、なければ文字列の2文字目以降でマッチする正規表現を探す」という動作をする、ということだと理解しました その結果[このように](https://regex101.com/r/RtFfFg/1)先頭と末尾でマッチの仕方に違いができてしまうんですね とても理解の助けになりました 詳細な回答をしてくださりありがとうございました
guest

0

正規表現のデフォルトの動作は、「最長一致」だからです、

投稿2018/09/10 22:13

CHERRY

総合スコア25171

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

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

willii

2018/09/11 04:34

最長一致というものは、「マッチするもののうち、最も長いものを結果とする」という動作だと理解しています [この正規表現の結果](https://regex101.com/r/WNa6zJ/1)が最長一致の動作によるもの、という回答の理解で合っていますでしょうか? もしそうならば、[この正規表現の結果](https://regex101.com/r/mbgHMG/1)のように`.111`のうち`.1`のみがマッチするようなマッチの仕方ではなく、`.111`全体がマッチするのではありませんか? もし回答の意味を取り違えていたら、ぜひ教えて頂きたいです よろしくお願いします
think49

2018/09/11 10:49

最長一致は関係ないと思います。 (\d|\d\d|\d\d\d) を評価した場合、最長の \d\d\d がマッチするわけではありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問