[PHP-users 20475]Re: 再帰(?)正規表現置換について

Osamu Shigematsu shige @ ravi.ne.jp
2004年 2月 20日 (金) 11:52:26 JST


重松です。こんにちは。

> > 最初に、' を ' に変換しておき、
> 
> なるほど、それでいけそうですね。
> テンプレート上で'と書いてあるものをもし変換せず保ちたかったら、
> 先に&→&、最後に&→&、の変換を一発入れるといいかなと思います。

& -> & などは必要ないのではと考えます。
というのは、目的は単に ' が含まれなくすることであり、php スクリプトにコ
ンパイル後に ' のまま残ったとしても、特に大きな問題にはならないと思
います。

が、肝心の stripslashes では、\ が欠落しました。
preg_replace の処理は、addslashes と等価ではないように思えます。
これ以上は、pcre のソースを読め、という事態になりそうなので、あまりに美
しくないのですが、str_replace 案で我慢しようと思います。

> 今回の話に限ると、再帰処理の場面では「そのパターン」のみが適用できればいい
> と思うので、replacement部分で「preg_replace(\$p[1], \$r[1], ...)」のように
> 添え字を直接指定する手で無駄が省けると思います。姑息な手段ですけれど。

そのように対策済みではあるのですが、見落としやすい部分ですね。

> > いえ、単に式の結果を捨てたいだけなんですが。
> 
> arrayの応用を幾つか考えてみましたが、その中で実際に機能した方法はこれです。
> function last(){return array_pop(func_get_args())}
> echo last(1,2,3,4,5);
> 
> ちなみに echo array_pop(array(1,2,3,4,5)); とかはエラーになりました。

以前、大垣さんが配列の生成はコストが高い処理だ、とおっしゃってましたので、
値を捨てるために array を一時的に生成するのはコストに見合わない気がする
のですが。まだベンチを取っていないのですが、

	(式 A) ? 式 B : ''

として、式 A を必ず真になるようにした上で、任意の処理をして、式 B で返し
たい値を返すほうがスマートだと思いました。

で、今回はこれをさらに応用して、{def}, {/def}, {each} を一発で置換してし
まうことにしました。

肝心の正規表現部分は以下のようになりました。

マッチさせるほうは単純ですが、置き換えるほうは、ちょっと複雑になってしま
いましたが、それでも、このコードの量できそれなりのテンプレートが実現でき
る正規表現という発明は本当にすばらしいですね。

function _parse($src)
{
	$p = array(
			'/\{([^\W_]\w*)\}/',
			'/<!--\{(each|(!?)def)\s+([^\W_]\w*)\}-->(((?>(?:(?!<!--{\/?\1\s+\3}-->).)+?)|(?R))*?)<!--\{\/\1\s+\3\}-->/se');
	$r = array(
			'<?php echo $\1; ?>',
			"('\\1'=='each' && \$dst.=('<?php function template_'.++\$i.'(\$_ary){foreach(\$_ary as \$_val){extract(\$_val,EXTR_REFS); ?>'.
preg_replace(\$p[1], \$r[1], str_replace('\\\"','\"','\\4')).
'<?php }} ?>')) ?  
'<?php template_'.\$i.'(\$\\3); ?>':
			'<?php if(\\2 @ count(\$\\3)){ ?>'.preg_replace(\$p[1],\$r[1],str_replace('\\\"','\"','\\4')).'<?php }?>'");
	$i = 0;
	$dst = '';
	return '<?php extract($_val, EXTR_REFS); ?>' . preg_replace($p, $r, $src) . $dst;
}

-- 
Osamu Shigematsu <shige @ ravi.ne.jp>



PHP-users メーリングリストの案内