我有一些由 DOMDocument::saveXML()
返回的 XML block 。它已经非常缩进了,每层有两个空格,如下所示:
<?xml version="1.0"?>
<root>
<error>
<a>eee</a>
<b>sd</b>
</error>
</root>
由于无法为缩进字符配置 DOMDocument
(AFAIK),因此我 thought it's possible to run a regular expression 并通过将所有两个空格对替换为制表符来更改缩进。这可以通过回调函数 (Demo) 来完成:
$xml_string = $doc->saveXML();
function callback($m)
{
$spaces = strlen($m[0]);
$tabs = $spaces / 2;
return str_repeat("\t", $tabs);
}
$xml_string = preg_replace_callback('/^(?:[ ]{2})+/um', 'callback', $xml_string);
我现在想知道是否可以在没有回调函数的情况下执行此操作(并且没有 e
-修饰符 (EVAL))。任何有想法的正则表达式向导?
最佳答案
你可以使用\G
:
preg_replace('/^ |\G /m', "\t", $string);
做了一些基准测试并在 Win32 上用 PHP 5.2 和 5.4 得到了以下结果:
>php -v
PHP 5.2.17 (cli) (built: Jan 6 2011 17:28:41)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies
>php -n test.php
XML length: 21100
Iterations: 1000
callback: 2.3627231121063
\G: 1.4221360683441
while: 3.0971200466156
/e: 7.8781840801239
>php -v
PHP 5.4.0 (cli) (built: Feb 29 2012 19:06:50)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
>php -n test.php
XML length: 21100
Iterations: 1000
callback: 1.3771259784698
\G: 1.4414191246033
while: 2.7389969825745
/e: 5.5516891479492
令人惊讶的是回调比 PHP 5.4 中的 \G
更快(尽管这似乎取决于数据,\G
在某些其他情况下更快)。
对于 \G
使用 /^ |\G/m
,比 /(?:^|\G)/m 快一点
。
/(?>^|\G)/m
比 /(?:^|\G)/m
还要慢。
/u
、/S
、/X
开关不会显着影响 \G
性能。
while
替换在深度较低时最快(在我的测试中最多约 4 个缩进,8 个空格),但随着深度的增加会变慢。
使用了以下代码:
<?php
$base_iter = 1000;
$xml_string = str_repeat(<<<_STR_
<?xml version="1.0"?>
<root>
<error>
<a> eee </a>
<b> sd </b>
<c>
deep
deeper still
deepest !
</c>
</error>
</root>
_STR_
, 100);
//*** while ***
$re = '%# Match leading spaces following leading tabs.
^ # Anchor to start of line.
(\t*) # $1: Preserve any/all leading tabs.
[ ]{2} # Match "n" spaces.
%mx';
function conv_indent_while($xml_string) {
global $re;
while(preg_match($re, $xml_string))
$xml_string = preg_replace($re, "$1\t", $xml_string);
return $xml_string;
}
//*** \G ****
function conv_indent_g($string){
return preg_replace('/^ |\G /m', "\t", $string);
}
//*** callback ***
function callback($m)
{
$spaces = strlen($m[0]);
$tabs = $spaces / 2;
return str_repeat("\t", $tabs);
}
function conv_indent_callback($str){
return preg_replace_callback('/^(?:[ ]{2})+/m', 'callback', $str);
}
//*** callback /e ***
function conv_indent_e($str){
return preg_replace('/^(?: )+/me', 'str_repeat("\t", strlen("$0")/2)', $str);
}
//*** tests
function test2() {
global $base_iter;
global $xml_string;
$t = microtime(true);
for($i = 0; $i < $base_iter; ++$i){
$s = conv_indent_while($xml_string);
if(strlen($s) >= strlen($xml_string))
exit("strlen invalid 2");
}
return (microtime(true) - $t);
}
function test1() {
global $base_iter;
global $xml_string;
$t = microtime(true);
for($i = 0; $i < $base_iter; ++$i){
$s = conv_indent_g($xml_string);
if(strlen($s) >= strlen($xml_string))
exit("strlen invalid 1");
}
return (microtime(true) - $t);
}
function test0(){
global $base_iter;
global $xml_string;
$t = microtime(true);
for($i = 0; $i < $base_iter; ++$i){
$s = conv_indent_callback($xml_string);
if(strlen($s) >= strlen($xml_string))
exit("strlen invalid 0");
}
return (microtime(true) - $t);
}
function test3(){
global $base_iter;
global $xml_string;
$t = microtime(true);
for($i = 0; $i < $base_iter; ++$i){
$s = conv_indent_e($xml_string);
if(strlen($s) >= strlen($xml_string))
exit("strlen invalid 02");
}
return (microtime(true) - $t);
}
echo 'XML length: ' . strlen($xml_string) . "\n";
echo 'Iterations: ' . $base_iter . "\n";
echo 'callback: ' . test0() . "\n";
echo '\G: ' . test1() . "\n";
echo 'while: ' . test2() . "\n";
echo '/e: ' . test3() . "\n";
?>
关于php - 使用 preg_replace 转换缩进(无回调),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8616594/