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

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

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

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

正規表現

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

Q&A

解決済

3回答

2597閲覧

PHP正規表現で「完全一致の単語」は除外できないのでしょうか?

gongitune3

総合スコア12

PHP

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

正規表現

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

0グッド

0クリップ

投稿2020/07/30 20:15

編集2020/07/30 22:22

正規表現で「完全一致の単語」を除外したいです。
数時間googleで検索しているのですが・・・本当に見つかりません。

正規表現 否定
という検索では「否定先読み」ばかりで「完全一致の単語」という方法が検索できませんので

正規表現 否定 -先読み
などのように先読みを検索しないなど工夫して試みているのですが、さっぱり見当たらないです。

イメージとしてはこのように「"world"以外の単語」の場合だけ一致をechoしたいのですが。

php

1$str = "helloworlds"; // "world" ではなく "worlds" になっているので一致としたい 2if ( preg_match( '{\Ahello(^world).+\z}', $str ) ) { // "world" という単語だけを否定したい 3 echo '一致'; 4}

###m.ts10806様へ
ご指摘の点、補足させていただきます。具体的な事例ですが以下の流れを汲んでおります。

3行目のコメントアウトに記載ございます通り、このURLパターンはitemに属するはずなのにuserに属すという結果になってしまうのです。

そのため14行目のパターンで、widgetiframeを除外する、という正規表現を目論みました。
それができれば3行目のパターンはitemに属してくれるという考えです。

このような経緯から、「単語の除外」について正規表現で質問させていただいたという次第です。

php

1// 次のようなURLが $pattern_wrapper のどのパターンに属すか確認するのが目的です 2$url = "https://www.example.com/taro/aaa-bbb-ccc/"; // こういうURLパターンが複数あります 3$url = "https://www.example.com/widget/iframe/taro/"; // このURLパターンから $result['kind']='item'; を得たのに、$result['kind']='user' を得てしまいます 4 5// URLの想定されるパターンを指定します 6$pattern_wrapper = [ 7 'example' => [ 8 'service' => [ 9 '{\Ahttps?://(www.)?example.com/.+}', 10 ], 11 'item' => [ 12 '{\Ahttps?://(www.)?example.com/widget/iframe/(?P<name>[^/]+)}', 13 ], 14 'user' => [ 15 '{\Ahttps?://(www.)?example.com/(?P<name>[^/]+)/(?P<id>[^/]+)}', 16 ], 17 ], 18 'example2' => [ 19 'service' => [ 20 '{\Ahttps?://example2.net/.+}', 21 ], 22 'drink' => [ 23 '{\Ahttps?://example2.net/drinks/(?P<id>[0-9]+)\z}', 24 ], 25 26 ], 27]; 28 29// 結果として次の値を取得します 30$result = ['service'=>null,'kind'=>null,'id'=>null,'name'=>null]; 31 32// $url がどのパターンに一致するか確認します 33foreach ( $pattern_wrapper as $service => $kind_depth ) { 34 foreach ( $kind_depth as $kind => $pattern_arr ) { 35 foreach ( $pattern_arr as $pattern ) { 36 if ( preg_match( $pattern, $url, $matches ) ){ 37 if ( $kind === 'service' ) { 38 $result['service'] = $service; 39 } else { 40 $result['id'] = $matches['id'] ?? ''; 41 $result['name'] = $matches['name'] ?? ''; 42 $result['kind'] = $kind; 43 } 44 } 45 } 46 } 47} 48var_dump($result);

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

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

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

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

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

m.ts10806

2020/07/30 20:50

対象の文字列から「world」をreplaceで削除して比較して違ったら「一致」じゃダメなんでしょうか。 無理やり正規表現使う内容ではないように思いますが・・・ もう少しパターンケースだしたほうが良いかと思います。
gongitune3

2020/07/30 21:19

そうですね、質問の内容が知りたいので、別のアプローチは今回は大丈夫そうです。アドバイスありがとうございます。
m.ts10806

2020/07/30 21:42

やりたいことだけ求めても欲しいアドバイスは得られないと思います。他に簡単なやり方があるならそれを提案されるのは当然です。熟練者ほどその傾向にあります。正規表現は副作用やヌケモレを考慮する必要があるので、可能なら使わないやり方を優先的に選択すべきです。 もしこのまま進めたいなら「やりたいやり方でなければならない理由」をきちんと記載してください。
gongitune3

2020/07/30 22:11

なるほど、長くなってしまうと思い、自分の判断で必要箇所のみ抜き出して質問してしまいました。すぐに編集させていただきますので、いましばらくお待ちください。
gongitune3

2020/07/30 22:23

質問を編集させて頂きました。経緯としてはこうなるのですが、いかがでしょうか。
otn

2020/07/31 11:56

/ は正規表現の特殊文字じゃないので、\ を付ける必要ないです。
gongitune3

2020/08/02 04:54

ネットではみんな付けていると思ったのですが、デリミタがスラッシュだから付けているのですね。ご忠告感謝いたします。
guest

回答3

0

ベストアンサー

現在のuserに設定している正規表現では、nameにwidgetが、idにiframeが入ることは避けられません。

これを解決するには、あなたが検索していた「否定先読み」を使います。たとえば、

Regex

1\Ahttps?://(www.)?example.com/(?!widget/)(?P<name>[^/]+)/(?!iframe/)(?P<id>[^/]+)

とすれば、(?!widget/)で「'widget/'が書かれていない位置」にマッチします。これだけだと、対象の文字列の複数の位置にマッチしますが、これより前に書かれたパターン\Ahttps?://(www.)?example.com/で位置が限定されます。

同様に、(?!iframe/)で「'iframe/'が書かれていない位置」にマッチします。これだけだと(後略)。

その結果、userに設定している正規表現がマッチするのは、「(前略)exaple.com/の直後にwidget/がなく、その直後にiframe/もない」ときに限定されるので、おそらくお望みの結果が得られます。

余談:

自分でやるとしたら、そんなに正規表現ですべてをやろうとはせず、マッチさせた後で、

PHP

1if ($matches['name'] === 'widget' || $matches['id'] === 'iframe') { 2 continue; 3} 4

のように処理をスキップさせますね。これなら、組み合わせを「||」にするのか「&&」にするのかなど柔軟に設定できますから。

投稿2020/07/31 00:20

Daregada

総合スコア11990

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

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

gongitune3

2020/07/31 00:41

一日以上かかり絶望していたので大変うれしく思います。ご説明つきで助かりました!余談のハイブリッド案も腹落ちです。ありがとうございました!
guest

0

先に$str !== "helloworld" でフィルタすればよいのでは?

投稿2020/07/30 21:38

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2020/07/30 22:06

あー絶対正規表現でやりたい人か^^; 否定の言明で同じことをすればよいです。
gongitune3

2020/07/30 22:12

すみません、正規表現で「完全一致の単語」の除外の方法を知りたい、というのが質問になっておりますので、その点ご配慮いただけますと幸いです。
gongitune3

2020/07/30 22:14

あはは、そうなんです。きっと熟練者の方からするともっと良い方法があるのだろうとは思いますが、初心者で応用力に欠けておりまして、ひとまずは思いついた方針で、と。
退会済みユーザー

退会済みユーザー

2020/07/30 22:17 編集

コメントした通りです。 否定の言明で、フィルタしてやればよいです。
guest

0

PHP

1foreach(["helloworlds","helloworld","helloword","halloworld"] as $str){ 2 echo $str; 3 print preg_match( '/\Ahello(?!world\z)/',$str)?"一致":"不一致"; 4 echo "<br>"; 5}

投稿2020/07/31 00:38

yambejp

総合スコア114829

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

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

gongitune3

2020/07/31 00:44

ずばり質問にお答えいただき感謝です。かっこに^を書いても否定してくれなかったんですね。 ちょうどベストアンサーを決めてしまいましたが、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問