正規表現にはいろいろと苦労させられます。
ここ最近の経験で難儀した例を共有したいと思います。
私もよく使う preg_match 関数ですが、「ハンドル名(:IDコード)」(文字列はアルファベット)といった形式の文字列を探していた時に、Mozilla 系のブラウザで頻繁に問題が発生しました。
ゲームのアカウント名などによく使われる文字「à、î、ë、é、ü など」のアキュート・アクセントを付した文字(国際文字)をうまく拾ってくれませんでした。
真っ先に書いた正規表現コードは「A-z」を「ハンドル名」のマッチ検索に使用しました。勝手に「A-z」はアクセントを付した文字(国際文字)にも一致すると想定していましたが、実際は全くそうはならないことがすぐにわかりました。
preg_match(
"/([A-Za-z -]+)?\s?\[?\(?:([A-Za-z0-9\-\_]+)\)?\]?/",
"Pokémon [:pokemon]", $matches);
// 0 => 'Pokémon [:pokemon123]', 1 => 'Pokémon', 2 => 'pokemon123'
上のようなコードは、誰でも思いつきで書けて、しかも普通に想定する一般的文字列には完ぺきに機能します。だから、一度うまく動くとこれで問題ないと過信してしまいがちです。
ゲームユーザーに多いのですが、「Pokémon GO」のようなよく知られた商標から、上手くモジってハンドル名をつける人によく出くわします。
国際文字にマッチさせるには、2か所ばかり正規表現を書き換えてやる必要がありました。
- マッチさせたい部分で「A-z」とやっていた箇所を「\pL」と書き換えます。
- u 修飾子を追加して、文字列を UTF-8 として扱われるようにします。
PHP 5.1.0 以降、UTF-8 モードを使う場合は、「\pL」はアルファベットの大文字・小文字、擬似文字を含む国際文字にマッチします。
書き換えた上の正規表現は次のような感じになります
preg_match(
"/([\pL -]+)?\s?\[?\(?:([\pL0-9\-\_]+)\)?\]?/u",
"Pokémon [:pokemon]", $matches);
// 0 => 'Pokémon [:pokemon]', 1 => 'Pokémon', 2 => 'pokemon'
単純な方法ですが、知っていると便利なこともありますので、活用する機会があったら使ってみてください。