* [PCRE] AutoLink用の正規表現: スペースや#記号が含まれていると 'x'(PCRE_EXTENDED) をつけている場合に挙動が変わる [#h13096e7] -ページ: BugTrack -投稿者: [[morikawa]] -優先順位: 低 -状態: 完了 -カテゴリー: 本体バグ -投稿日: 2003-12-08 (月) 09:29:22 -バージョン: #contents ** 修正 [#tcb7de21] AutoLink用の正規表現について、 「正規表現の中で空白やコメント文を使用できるようにする」ためのオプション 'x'(PCRE_EXTENDED) を使用しているため、それらを適切にエスケープしないとうまく動作しないケースがある事がわかりました。 (1.4.3) - [[cvs:func.php]](r1.57-1.58) -- 半角スペースについて別途エスケープする (1.4.8) - [[cvs:lib/func.php]] (1.95, 1.98, 1.99) -- white space と # についてエスケープする ** [1.4.3] ページ名が英数字で間にスペースがあると、autolink でマッチしない [#hb97b30d] autolink.dat のスペースをエスケープしたらOKそうでした。 autolink.dat ...|InterWikiテクニカル|Wen Jiabao|ヘルプ|整形ルール|日本語) ...|InterWikiテクニカル|Wen\ Jiabao|ヘルプ|整形ルール|日本語) ---- -PCRE_EXTENDED(エスケープするか 文字クラスの内部にある場合を除き、 パターンの空白文字は完全に無視する)を指定しているので、空白もエスケープする必要がありました。preg_quoteには追加のエスケープ文字がひとつしか指定できないので、str_replace(' ','\\ ',...)を通すようにしました。 -- [[ぱんだ]] &new{2003-12-10 (水) 09:42:34}; -cvsに投入しました。[[cvs:func.php]](v1.4:r1.57) func.phpを差し替えた後、適当なページを更新してautolink.datを再構築してください。 -- [[ぱんだ]] &new{2003-12-10 (水) 09:42:34}; --[[v1.4:r1.57]]で、とりあえずページ名が英数字で間にスペースがある場合に関してはOKそうです。 -- [[morikawa]] &new{2003-12-11 (木) 11:30:26}; -v1.4:r1.57導入すると''「ほげ」''とか''ほげ・げほ''とかがAutoLinkかからないような感じですがCVS難民なだけでしょうか。ダウングレードで元に戻りました。 -- [[たらこせる]] &new{2003-12-10 (水) 11:11:35}; -たらこせるさんと同じく、v1.4:r1.57導入で一部のページがAutoLinkに掛からなくなりました。1.56に戻すと直ります。どのページ名がAutoLinkに掛からないかを挙げれば解決に役立つでしょうか? -- [[司書]] &new{2003-12-14 (日) 01:59:11}; -v1.4:r1.57での変更点(557行目)にtypoがあります。そのせいで生成する正規表現が文字化けしてAutoLinkがおかしくなります。 -- [[ようか]] &new{2004-01-30 (金) 23:48:11}; -$result .= str_replace(' ','\\ ',preg_quote(substr($pages[$i],$pos),'/')); +$result .= str_replace(' ','\\ ',preg_quote(mb_substr($pages[$i],$pos),'/')); --[[BugTrack/514]]もこれで直りました。 -- [[reimy]] &new{2004-01-31 (土) 21:51:43}; -cvsに投入しました。[[cvs:func.php]](v1.4:r1.58) -- [[ぱんだ]] &new{2004-02-29 (日) 23:11:57}; - BugTrack2/319 ([[下>#jeddb01c]]に移動) //#comment ---- ** [1.4.8] AutoAlias 利用時に、generate_trie_regex 関数が返す正規表現が、うまく動作しない場合がある [#jeddb01c] AutoAlias 導入前は、ページ名に''#'' が使えないこともあって、generate_trie_regex 関数が''#'' をエスケープしていなくても問題がありませんでした。 しかし、[[#01>test/01]] のように((例なので、短めのルールを書いています)) 別名に''#'' を含むAutoAlias 設定をすると、AutoAlias の正規表現にエスケープされていない''#'' が現れ、&br;InlineConverter クラスで使用する際にパターン修飾子x (PCRE_EXTENDED) によって''#'' 以降がコメント扱いされて正規表現に不整合が発生し、エラーとなります。 generate_trie_regex 関数を if ($index < ($i - 1)) { // Some more keys found // Recurse $regex .= str_replace(array(' ','#'), array('\\ ','\\#'), preg_quote($char, '/')) . generate_trie_regex($array, $index, $i, $pos + 1); } else { // Not found $regex .= str_replace(array(' ','#'), array('\\ ','\\#'), preg_quote(mb_substr($array[$index], $pos), '/')); } として''#'' もエスケープするようにすると、正常に表示されるようになりました。 -- 名無しさん &new{2009-03-20 (金) 00:21:26}; -------- - 把握しました。CVSリポジトリも追いました。こちらは [[BugTrack/502]] の続きのようですので、そこに集約しましょう((いつ誰がやってもいいですが、自分は今日はここまで))。zzz -- [[henoheno]] &new{2009-03-25 (水) 23:57:13}; - BugTrack2/319 よりコピーしました。&br;ところで、[[cvs:lib/func.php]] (1.94) のChangeLog は「generate_trie_regex(): More readable comments」となっていて、実際にコメントの修正以外は入っていないみたいなんですが・・・ -- 名無しさん &new{2009-03-26 (木) 17:35:23}; -- すみません。履歴を追いかけただけで修正はこれから~、な状態みたいですね。 -- 名無しさん &new{2009-03-26 (木) 22:04:27}; - [[cvs:lib/func.php]] (1.95, 1.98, 1.99): preg_quote_extended() を追加。上のメッセージに対比させる形で取り上げるならば、こういう修正になります。 +// preg_quote(), and also escape PCRE_EXTENDED-related chars +// REFERENCE: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php +// REFERENCE: http:// www.php.net/manual/en/reference.pcre.pattern.modifiers.php +// NOTE: Some special whitespace characters may warned by PCRE_EXTRA +// because of mismatch-possibility between PCRE_EXTENDED and '[:space:]#'. +function preg_quote_extended($string, $delimiter = NULL) +{ + // Escape some more chars + $regex_from = '/([[:space:]#])/'; + $regex_to = '\\\\$1'; + + if (is_string($delimiter) && preg_match($regex_from, $delimiter)) { + $delimiter = NULL; + } + + return preg_replace($regex_from, $regex_to, preg_quote($string, $delimiter)); +} + // Generate one compact regex for quick reTRIEval, // that just matches with all $array-values. // @@ -647,13 +663,11 @@ if ($index < ($i - 1)) { // Some more keys found // Recurse - $regex .= str_replace(' ', '\\ ', preg_quote($char, '/')) . + $regex .= preg_quote_extended($char, '/') . generate_trie_regex($array, $index, $i, $pos + 1); } else { // Not found - $regex .= str_replace(' ', '\\ ', - preg_quote(mb_substr($array[$index], $_pos), '/')); + $regex .= preg_quote_extended(mb_substr($array[$index], $_pos), '/'); } $index = $i; } -- 今までの経緯からすると、PCRE_EXTENDED の仕様を認識していたにもかかわらず、関連する対象文字を全てカバーしていなかったというのが問題のように見えます。足りないケアは # についてだけではないので、#を足すだけでは解決にはなりません。そこで、最終的に[:space:]と#についても追加でエスケープする関数 preg_quote_extended() を用意しました。これで、generate_trie_regex() がもう少し汎用化された関数になったはずです。 ((とっくに汎用化したと思っていたのに・・・。 http://www.pcre.org/pcre.txt によると、 \s は Perlとの互換性を維持するため VT <vertical tab> 文字を含んでいません。[:space:] は含んでいます。)) -- [[henoheno]] &new{2009-03-29 (日) 11:46:53}; -- 今までの経緯からすると、PCRE_EXTENDED の仕様を認識していたにもかかわらず、関連する対象文字を全てカバーしていなかったというのが問題のように見えます。足りないケアは # についてだけではないので、#を足すだけでは解決にはなりません。そこで、最終的に[:space:]と#についても追加でエスケープする関数 preg_quote_extended() を用意しました。これで、generate_trie_regex() がもう少し汎用化された関数になったはずです。 ((とっくに汎用化したと思っていたのに・・・。 http:// www.pcre.org/pcre.txt によると、 \s は Perlとの互換性を維持するため VT <vertical tab> 文字を含んでいません。[:space:] は含んでいます。)) -- [[henoheno]] &new{2009-03-29 (日) 11:46:53}; -- 補足: PCRE_EXTENDED が無視する whitespace と、 [:space:] に属するwhitespaceにはひょっとしたら多少のずれがあるかもしれません。そしてそのずれが、PCRE_EXTRA によりエラーとして報告される事があるかもしれません。現状は無害((こうした正規表現から「文字列の配列」を取り戻そうとした場合には、余計なバックスラッシュが邪魔になる))であろうため、今回そこまでは追っていません。 -- [[henoheno]] &new{2009-03-29 (日) 11:55:17}; - lib/func.php (1.100) で、特に問題はないことを確認しました。 -- 名無しさん &new{2009-03-30 (月) 22:24:34}; - CzMaPgfOzhNLKbrVvR -- [[qwqjrmr]] &new{2014-09-05 (金) 00:46:07}; #comment //#comment *** その他: [#tb4ec63c] - 本件に付随し、generate_trie_regex() について若干の整理を行いました。他の修正とはdiffが別になるようにcommitしてあります。詳細はdiffを見て下さい -- [[henoheno]] &new{2009-03-29 (日) 11:57:34}; -- [[cvs:lib/func.php]] (1.94) 関数ヘッダの整理 -- [[cvs:lib/func.php]] (1.96) 文字列の連結方法を修正 (ページが大量にある場合、若干処理が早くなる) ((preg_quote_extended() を外出しにしたため、トータルでは遅いはず)) -- [[cvs:lib/func.php]] (1.97) 内部変数の名前をそれらしく修正 -- [[cvs:lib/func.php]] (1.100) "if (mb_substr($array[$i], $_pos, 1) != $char)" を関数呼び出しの度に一回以上余計に実行していた - 本件に付随し、generate_trie_regex() をもう少し観察し直しましたが、正規表現が無駄に長くなる場面があります。以下のような処理をさせるためには、作り直さないと実現できないでしょう -- [[henoheno]] &new{2009-03-29 (日) 12:10:39}; こうなる部分は (?:1(?:0|1|2|3|4|5|6|7|8|9)|2(?:0|1|2|3|4|5|6|7|8|9)) 本来こうできる [12][0-9] -- そもそもこうした(木構造を正規表現に落とし込むような)機構は誰かがライブラリ化しているものではないのかな・・・ -- [[henoheno]] &new{2009-03-29 (日) 12:18:10}; #comment //#comment