[PCRE] AutoLink用の正規表現: スペースや#記号が含まれていると 'x'(PCRE_EXTENDED) をつけている場合に挙動が変わる

  • ページ: BugTrack
  • 投稿者: morikawa
  • 優先順位: 低
  • 状態: 完了
  • カテゴリー: 本体バグ
  • 投稿日: 2003-12-08 (月) 09:29:22
  • バージョン:

修正

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 でマッチしない

autolink.dat のスペースをエスケープしたらOKそうでした。

autolink.dat

...|InterWikiテクニカル|Wen Jiabao|ヘルプ|整形ルール|日本語)
...|InterWikiテクニカル|Wen\ Jiabao|ヘルプ|整形ルール|日本語)

  • PCRE_EXTENDED(エスケープするか 文字クラスの内部にある場合を除き、 パターンの空白文字は完全に無視する)を指定しているので、空白もエスケープする必要がありました。preg_quoteには追加のエスケープ文字がひとつしか指定できないので、str_replace(' ','\\ ',...)を通すようにしました。 -- ぱんだ 2003-12-10 (水) 09:42:34
  • cvsに投入しました。cvs:func.php(v1.4:r1.57) func.phpを差し替えた後、適当なページを更新してautolink.datを再構築してください。 -- ぱんだ 2003-12-10 (水) 09:42:34
    • v1.4:r1.57で、とりあえずページ名が英数字で間にスペースがある場合に関してはOKそうです。 -- morikawa 2003-12-11 (木) 11:30:26
  • v1.4:r1.57導入すると「ほげ」とかほげ・げほとかがAutoLinkかからないような感じですがCVS難民なだけでしょうか。ダウングレードで元に戻りました。 -- たらこせる 2003-12-10 (水) 11:11:35
  • たらこせるさんと同じく、v1.4:r1.57導入で一部のページがAutoLinkに掛からなくなりました。1.56に戻すと直ります。どのページ名がAutoLinkに掛からないかを挙げれば解決に役立つでしょうか? -- 司書? 2003-12-14 (日) 01:59:11
  • v1.4:r1.57での変更点(557行目)にtypoがあります。そのせいで生成する正規表現が文字化けしてAutoLinkがおかしくなります。 -- ようか? 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),'/'));
  • cvsに投入しました。cvs:func.php(v1.4:r1.58) -- ぱんだ 2004-02-29 (日) 23:11:57
  • BugTrack2/319 (に移動)

[1.4.8] AutoAlias 利用時に、generate_trie_regex 関数が返す正規表現が、うまく動作しない場合がある

AutoAlias 導入前は、ページ名に# が使えないこともあって、generate_trie_regex 関数が# をエスケープしていなくても問題がありませんでした。

しかし、[[#01>test/01]] のように*1 別名に# を含むAutoAlias 設定をすると、AutoAlias の正規表現にエスケープされていない# が現れ、
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), '/'));
		}

として# もエスケープするようにすると、正常に表示されるようになりました。 -- 名無しさん 2009-03-20 (金) 00:21:26


  • 把握しました。CVSリポジトリも追いました。こちらは BugTrack/502 の続きのようですので、そこに集約しましょう*2。zzz -- henoheno 2009-03-25 (水) 23:57:13
  • BugTrack2/319 よりコピーしました。
    ところで、cvs:lib/func.php (1.94) のChangeLog は「generate_trie_regex(): More readable comments」となっていて、実際にコメントの修正以外は入っていないみたいなんですが・・・ -- 名無しさん 2009-03-26 (木) 17:35:23
    • すみません。履歴を追いかけただけで修正はこれから~、な状態みたいですね。 -- 名無しさん 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
    +// 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() がもう少し汎用化された関数になったはずです。 *3 -- henoheno 2009-03-29 (日) 11:46:53
    • 補足: PCRE_EXTENDED が無視する whitespace と、 [:space:] に属するwhitespaceにはひょっとしたら多少のずれがあるかもしれません。そしてそのずれが、PCRE_EXTRA によりエラーとして報告される事があるかもしれません。現状は無害*4であろうため、今回そこまでは追っていません。 -- henoheno 2009-03-29 (日) 11:55:17
  • lib/func.php (1.100) で、特に問題はないことを確認しました。 -- 名無しさん 2009-03-30 (月) 22:24:34

その他:

  • 本件に付随し、generate_trie_regex() について若干の整理を行いました。他の修正とはdiffが別になるようにcommitしてあります。詳細はdiffを見て下さい -- henoheno 2009-03-29 (日) 11:57:34
    • cvs:lib/func.php (1.94) 関数ヘッダの整理
    • cvs:lib/func.php (1.96) 文字列の連結方法を修正 (ページが大量にある場合、若干処理が早くなる) *5
    • cvs:lib/func.php (1.97) 内部変数の名前をそれらしく修正
    • cvs:lib/func.php (1.100) "if (mb_substr($array[$i], $_pos, 1) != $char)" を関数呼び出しの度に一回以上余計に実行していた
  • 本件に付随し、generate_trie_regex() をもう少し観察し直しましたが、正規表現が無駄に長くなる場面があります。以下のような処理をさせるためには、作り直さないと実現できないでしょう -- henoheno 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 2009-03-29 (日) 12:18:10

*1 例なので、短めのルールを書いています
*2 いつ誰がやってもいいですが、自分は今日はここまで
*3 とっくに汎用化したと思っていたのに・・・。 http:// www.pcre.org/pcre.txt によると、 \s は Perlとの互換性を維持するため VT <vertical tab> 文字を含んでいません。[:space:] は含んでいます。
*4 こうした正規表現から「文字列の配列」を取り戻そうとした場合には、余計なバックスラッシュが邪魔になる
*5 preg_quote_extended() を外出しにしたため、トータルでは遅いはず

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-09-05 (金) 00:46:07
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.213 sec.

OSDN