dポイントプレゼントキャンペーン実施中!

とあるサイトで、
「URL からドメイン名を得る」という項目があったのでマネして
やってみたらうまくいきました。しかし正規表現パターンの意味は
理解できませんでしたので理解できなかった部分だけをのせたスクリプトを以下にまとめました。
<?php
// まずUPLからホスト名を得る
preg_match('@^(?:http://)?([^/]+)@i',
"http://www.nantoka.com/index.html", $matches);
$zenbu=$matches[0];
$host = $matches[1];
$saigo=$matches[2];
/*必要なのはホスト名だけですが、$matches[0]や$matches[2]には
どんな文字列が格納されるか気になって出力することにしました*/
print($zenbu);
print("<br/>");
print($host);
print("<br/>");
print($saigo);
print("<br/>");
?>

これを実行した結果は、
$zenbuが「http://www.nantoka.com」で、
$hostが「www.nantoka.com」で、
$saigoがなにもなしでした。


このスクリプトでわからない部分は、'@^(?:http://)?([^/]+)@i'の部分と、$host = $matches[1];の部分です。

まず正規表現パターンの最初のアットマークの後ろの^は「次の文字列からはじまる」と解釈しました。
最後のアットマークの後ろのiは、「大文字と小文字を区別しない」という意味だと解釈しました。
カッコで囲まれている(?:http://)と、([^/]+)は、サブマッチパターン
だと思いました。
$matches[0]には、"http://www.nantoka.com/index.html"
中で'@^(?:http://)?([^/]+)@i'に当てはまるもの全体が格納され、
$matches[1]には、(?:http://)に当てはまるもの、
$matches[2]には、([^/]+)に当てはまるものが格納されると考えました。
[^/]+は、「スラッシュを含まない文字が1文字以上」と解釈しました。
ただ、その他の事については考えましたがよくわからず、
特になんで(?:http://)にあたるものが「www.nantoka.com」
になるのかさっぱりわかりません。
(?:http://)の中にあるhttp://の前の?:が一体何なのか、
(?:http://)と([^/]+)の間にある?は何なのか、
両端のアットマークは何なのか(マッチ演算子かと思って
スラッシュに置き換えて実行してみたらエラーになりました。)
うまく説明できませんがとにかくその辺のことがよくわかりませんでした。どなたか教えていただけませんか。

A 回答 (3件)

と、その他の部分も補足します。



まず、@ですが、正規表現のマッチングの場合、マッチング対象を囲みます。
通常は、「/」を使うのですが、今回のマッチング文字列の中に「/」が含まれているため、代替として「@」を使っているのだと思います。
マッチ演算子として、「/」に戻した場合、内部の「http://」の「/」を¥マークでエスケープしないとエラーになってしまうと思います。

つづいて、(?:http://)の後の?ですが、これは「この?の前にあるブロックが、0~1回出てくること」という条件になります。
なので、http://http://aaaという文字列を入れた場合、http://を1回分だけよりわける、ということが出来るようになります。
    • good
    • 0
この回答へのお礼

エラーの詳細まで教えていただき感謝しています。
http://の後の?についても確かめてみました、
(なんのためにhttp://が2つもあったりhttp://がなかったりするのか
はよくわかりませんが、検索したら実際にそういうものがありますね。)

お礼日時:2007/12/09 11:35

@はここでは、正規表現の始まりと終わりを示すものとして使われています。


通常この目的には '/' が使われることが多いのですが、今回マッチングに
使用するパターンに '/' が複数含まれているのでエスケープのバックスラッシュを
多用することによって見づらくなるのを避けるために'@' を使用したのでしょう。

$matches[0], $matches[1], $matches[2], ... ですが

0 → パターンにマッチした全体
1 → 1番目のサブパターンに捕獲された部分文字列
2 → 2番目のサブパターンに捕獲された部分文字列

となります。ここで、(?: ) と ( ) とは違うものだということに注意してください。
(?: ) によりグループ化された場合、捕獲はなされません。つまり、


> $matches[1]には、(?:?http://)?に当てはまるもの、
> $matches[2]には、([^/]+)に当てはまるものが格納されると考えました。

これがひとつずれます。$matches[1] には ([^/]+)によって捕獲されたものであり、
このパターンには捕獲を行うグループ化はひとつしかありませんので、
$matches[2]は常に空になります。

順番が前後しましたが、'(?:' の三文字で捕獲をしないグループ化を表す
メタ文字になってます。ですので '?:' それ自体に意味はありません。
    • good
    • 0
この回答へのお礼

「捕獲をしないグループ化」というところが非常にわかりやすくて頭の中にしっかり残りました。ありがとうございます。

お礼日時:2007/12/09 11:20

まさにossuさんがわからない、といっていた「?:」がこの部分の肝となります。



(?:~~~)とすると、この括弧の部分を検索時のマッチ対象から外すことが出来るようになります。
このため、$matches[1]に本来、$matches[2]に入る内容が入ってくることになります。

詳しくは、PHPマニュアルをご覧下さい。

参考URL:http://search.net-newbie.com/php/reference.pcre. …
    • good
    • 0
この回答へのお礼

ありがとうございます。まさかそんなことが出来るとは思いませんでした。

お礼日時:2007/12/09 11:14

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!