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

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

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

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

正規表現

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

Q&A

解決済

4回答

10787閲覧

正規表現で特定文字1文字の場合のみマッチする書き方

kitsunekonkon

総合スコア29

PHP

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

正規表現

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

0グッド

3クリップ

投稿2015/09/30 07:53

phpのpreg_match関数で

あいうえお!!

かきくけこ!?

などの感嘆符、疑問符ひとつ以上の時はマッチせず、

あいうえお!
かきくけこ?

など感嘆符、疑問符がひとつだけのときはマッチする

という条件でif文で判定したいのですが、

preg_match('/[!\?]?/', $string)

で感嘆符や疑問符ひとつだけの時を判定しようとしても

あいうえお!

のような文字列に引っかかってくれません。

特定の文字がひとつだけの場合は引っかかり、2つ以上連続するときは引っかからないような正規表現はどのように書いたらよろしいでしょうか??

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

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

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

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

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

guest

回答4

0

ベストアンサー

こんな感じでどうでしょう?

対象の文字列に「感嘆符、疑問符が一つだけの部分文字列」が含まれていればマッチし、
マッチした場合は、見つかった文字列を配列として取得します。

php

1<?php 2 3$data = array( 4 "", "!", "&", "!!", "&&", "!!!", "&&&", 5 "あいうえお!", 6 "あいうえお?", 7 "あいうえお!!", 8 "あいうえお!?", 9 "あいうえお??", 10 "あいうえお?!", 11 "あいうえお???", 12 "あいうえお!??", 13 "あいうえお?!?", 14 "あいうえお??!", 15 "あいうえお!!!", 16 "あい!うえ!!おかき!?くけこさ?しすせそ", 17 "!あいうえお!", 18 "!あいうえお!!" 19); 20 21foreach($data as $subject) { 22 print "=== string : {$subject} ===" . PHP_EOL; 23 $pattern = "/(?![^!?]+([!?]{2,}))[^!?]+[!?]/"; 24 if (preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)) { 25 print_r($matches); 26 } 27}

正規表現部分の説明です。

php

1$pattern = "/(?![^!?]+([!?]{2,}))[^!?]+[!?]/";

前半の「(?![^!?]+([!?]{2,}))」が否定先読みにより
「後ろに感嘆符か疑問符の組み合わせを二つ以上持つ、感嘆符、疑問符を含まない文字列」
をマッチさせないようにして、

後半の「[^!?]+[!?]」により
「後ろに感嘆符か疑問符を一つ持つ、感嘆符と疑問符を含まない文字列」
にマッチさせるようにしています。

簡単なテストデータなのでバグがないとも言い切れませんが、
参考になれば幸いです。

※補足
正確には先読みや否定先読みは位置にマッチするので、今回の正規表現は、
「後ろに感嘆符か疑問符の組み合わせを二つ以上持つ、感嘆符、疑問符を含まない文字列」
にマッチしない位置を表し、その位置と後半の正規表現を合わせた条件になるようです。

投稿2015/10/01 00:38

編集2015/10/01 12:53
StupidDog

総合スコア263

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

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

kitsunekonkon

2015/10/06 04:12

StupidDog様 お返事遅れてしまって大変申し訳ございません。 記載していただいた通りの正規表現で意図通りのプログラムがかけました! ありがとうございます。またこちらの回答をベストアンサーにさせていただきます。 本当に助かりました。
guest

0

否定先読み、否定戻り読みを使ってこういうのどうでしょう?

<?php if (preg_match('/(?<! [!?])[!?](?![!?])/', 'あいうえお!!')) echo '1にマッチしました。'; if (preg_match('/(?<! [!?])[!?](?![!?])/', 'あいうえお!')) echo '2にマッチしました。'; ?> //teratail上での表示が壊れるので、?<![!?] の!と[の間にスペースを入れています。

所で感嘆符にだけHITすればよかったのでしょうか?
コード中の2でHITしているのは「あいうえお!」ではなくて、「!」です
単独の感嘆符が存在するかどうかを判定ですだけならいいのですが、
HITする部分を抽出して処理する場合不十分かも知れません

投稿2015/09/30 11:38

編集2015/09/30 11:54
hirohiro

総合スコア2068

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

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

hirohiro

2015/09/30 11:39

否定先読み投稿すると表示がバグる? 画像添付のコードと被ってるのかも知れません。修正中
kitsunekonkon

2015/10/01 02:12

hirohiro様 ありがとうございます。否定先読み、戻り読みというもの自体初めて知りました。 勉強になります。 hirohiro様のおっしゃるとおり、HITする部分を抽出する必要があるので、少し修正する必要がありそうです。
guest

0

maisumakun様の回答では、連続している"!?"のうち、一番後ろの"!?"がマッチしてしまいます。

質問者様の意図として、
文字列の末尾の"!?"だけをチェックしたい(文字列の途中に"!?"が含まれる場合は考慮しない)
のであれば、
以下の正規表現で実現できると思います。

php

1/[^!?][!?]$/

投稿2015/09/30 09:30

KiyoshiMotoki

総合スコア4791

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

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

kitsunekonkon

2015/09/30 09:47

KiyoshiMotoki様 ありがとうございます! 文字列末尾の!や?だけをチェックすることでほとんどの場合は問題ないかと思いますが、 純粋に文中にも末尾にも!や?が存在する場合に 連続してたらマッチしない。 ひとつだけならマッチする。 という条件で判定する場合はどのようになりますでしょうか? このような場合正規表現で全てを一気に判定するよりも、文中の場合と文字列末尾の場合で条件を分けて記述したほうが、簡単でしょうか?
KiyoshiMotoki

2015/09/30 10:52 編集

文中の"!?"もチェックしたい場合は、以下のようになります。 ```php /(^|[^!?]*)[!?]([^!?]*|$)/ ``` ただし、2点問題があり、 1. この場合は 複数箇所に分かれて"!"または"?"が現れた場合にもマッチしてしまいます。 (文中にただ1回だけ"!"または"?"が現れるのを許容する、という要件に対応できない) ```php $string = 'あいうえお! かきくけこ?'; preg_match('/(^|[^!?]*)[!?]([^!?]*|$)/', $string); // マッチする ``` それで問題ないなら構わないですが、そうでないなら`substr_count`または`mb_substr_count`で"!"と"?"の出現回数を調べた方が簡単だと思います。 http://php.net/manual/ja/function.substr-count.php http://php.net/manual/ja/function.mb-substr-count.php 2. ちゃんと動作確認していませんw
kitsunekonkon

2015/09/30 11:14

KiyoshiMotoki様 なるほど!文中の中で使う場合は制約が出てしまうのですね。 とりあえず教えていただいた方法で試してみます。 意図した通りにいかないようであれば、mb_substrなどを使ってやってみます! ありがとうございました(^^)
guest

0

PCREには、言明という機能があって、「あとに特定のパターンが続かない」ことを(?!パターン)の形で宣言できます。

php

1//あとに同種の記号が続かない感嘆符・疑問符にヒット 2preg_match('/[!?](?![!?])/', $string)

なお、角カッコ内での特殊文字は、閉じ角カッコ以外エスケープ不要です。

投稿2015/09/30 08:05

編集2015/09/30 08:07
maisumakun

総合スコア145183

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

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

kitsunekonkon

2015/09/30 08:55

ありがとうございます! 教えていただいたように下記のようなコードで試してみましたが、なぜか感嘆符が連続している場合にも引っかかってしまいます。 以下が実行してみたコードです。 ``` <?php if (preg_match('/[!?](?![!?])/', 'あいうえお!!')) { echo 'マッチしました。'; } else { echo 'マッチしませんでした。'; } ``` 結果 ``` マッチしました。 ``` どこか書き方が間違っているのでしょうか? ご教示いただけると助かります。 よろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問