PHPのPCRE関数にあるUTF-8モードが厄介な件
- kim_upsilon
- 10991
- 2
- 5
- 8
事の発端はあるバグチケットから
発端となったのはこのバグから。
大雑把に説明すると、
「http://example.comあああ」
といふ文字列に対して自動リンク機能を通したところ
「<a href="http://example.com">http://example.com</a>あああ」
ではなく
「<a href="http://example.comあああ">http://example.comあああ</a>」
のような残念な感じにリンクが張られてしまふといふバグである。
このバグを報告し終へた後、単純な正規表現のミスだらうと高を括って修正に取り掛かってゐた。が、原因が一向に掴めない。
そこで、次のやうなPHPコードを実行したところ preg_match が奇妙な挙動をすることに気がついた。
<?php
preg_match('/^([[:alnum:]]*)([[:^alnum:]]*)$/u', 'aaaaああああ', $match);
var_dump($match);
結果は次のとほりになる (PHP 5.4.4)
array(3) {
[0] =>
string(16) "aaaaああああ"
[1] =>
string(16) "aaaaああああ"
[2] =>
string(0) ""
}
をかしい、どう見ても [[:alnum:]] にひらがながマッチしてゐる。
ちなみに、正規表現の末尾に付いてゐる「u」は UTF-8 モード を有効にするオプションで、始めに書いた自動リンク機能の正規表現でも使はれてゐる。(参照: PHP: 正規表現パターンに使用可能な修飾子 - Manual)
「\w」はロケール依存なのか / PHP: エスケープシーケンス - Manual http://t.co/VedWsfM9
2012-12-27 17:10:11「UTF-8 モードでは、128 より大きなコードはどの POSIX 文字クラスにもマッチしません。」って書いてあるのにーーーー / PHP: 文字クラス - Manual http://t.co/lNZ6IQFj
2012-12-27 18:39:58/([[:alnum:]]*)([[:^alnum:]]*)/u と書くとですね、「aaaaああああ」だと \1 が 'aaaaああああ' で \2 が '' になるんですよ。これってトリビアになりませんかね
2012-12-27 18:43:33ここで海老原さん (@co3k) から手掛かりが
@kim_upsilon http://t.co/dEOawVG9 読む限り [:alnum:] が \p{Xan} になるモードがあるようなので、コンパイル時にそういうフラグが立っちゃってるとかですかね?
2012-12-27 18:44:49U+3042 は Other_Letter カテゴリに含まれるので Xan が L と N の組み合わせってことならマッチしそう
2012-12-27 18:57:19http://www.pcre.org/pcre.txt を読んでみると、PCRE_UCP オプションとやらが有効になってゐる場合には [:alnum:] は \p{Xan} と同等に解釈されると書かれてゐる。
\p{Xan} はひらがなもマッチするやうなので、どこかで PCRE_UCP が使はれてゐるのが原因であると見てよささうだ。さうなれば PCRE_UCP の出所さえ分かれば原因が掴めるか。
PHP の当該ソースを読んでみる
ext/pcre/php_pcre.c のUTF-8モードに関係する箇所 (359行目から366行目)
https://github.com/php/php-src/blob/master/ext/pcre/php_pcre.c#L359-366
. \d,\D, \s, \S, \w, and \W recognize only ASCII characters, even in UTF-8 mode. However, this can be changed by setting the PCRE_UCP option
2012-12-27 19:10:08そこで見たものは、「u」オプションによって無慈悲にも PCRE_UTF8 とともに問答無用で追加される PCRE_UCP オプションであった。
PHP では UTF-8 モードを使用する以上、PCRE_UCP オプションも強制的に有効となってしまふのだ。
といふことで、 http://t.co/lNZ6IQFj にあった「UTF-8 モードでは…」は PCRE_UCP が無かった頃の話で今はさうでもないと
2012-12-27 19:12:47@co3k 解決しました。ありがとうございます。UTF-8モード有効時にPCREに PCRE_UCP オプションが渡されるようになったことが原因でした https://t.co/oHXmurB5
2012-12-27 19:20:32