在下面的示例中,PHP比Rust快5.5倍。
我是从根本上做错了吗?
对我来说,Rust中的正则表达式引擎似乎比PHP中的慢。
PHP代码:
$html = file_get_contents('/path_to/test.html');
global $c_id;
$c_id = 0;
echo 'len with comments: ', strlen($html), "\n";
$time_start = microtime(true);
$html = preg_replace_callback('/<!--(.*?)-->/s', function($matches) {
global $c_id;
$c_id++;
return str_replace($matches[1], $c_id, $matches[0]);
}, $html);
echo (microtime(true) - $time_start), " seconds for removing comments.\n";
echo 'len without comments: ', strlen($html), "\n";
锈码:
use regex::Regex;
use std::io::prelude::*;
use std::fs::File;
fn main() {
let mut file = File::open("/path_to/test.html").expect("Unable to open the file");
let mut html = String::new();
file.read_to_string(&mut html).expect("Unable to read the file");
let mut c_id: usize = 0;
println!("len with comments: {}", html.len());
let start = PreciseTime::now();
let re = Regex::new(r"(?s)<!--(.*?)-->").unwrap();
html = re.replace_all(&html, |captures: ®ex::Captures| {
c_id += 1;
captures[0].replace(&captures[1], &c_id.to_string())
}).to_string();
println!("{} seconds for removing comments.", start.to(PreciseTime::now()));
println!("len without comments: {}", html.len());
}
Rust依赖项:
regex = "1"
time = "*"
结果
PHP:
len with comments: 76968
0.00019717216491699 seconds for removing comments.
len without comments: 76622
铁锈:
len with comments: 76968
PT0.001093365S seconds for removing comments.
len without comments: 76622
谢谢!
这可能是由于在Rust regex中实现了惰性模式扩展。请注意,懒惰的(.*?)
模式的工作方式如下:首先将其跳过,然后正则表达式引擎将尝试后续的模式,即-->
。如果-->
之后不存在<!--
,则正则表达式引擎返回(.*?)
,在<--
之后获取下一个字符,并将其放入第1组的单独的内存缓冲区中,然后再次重试以与之匹配-->
失败后返回,将char与.*?
匹配,并修改组1内存缓冲区,依此类推。因此,第1组内存缓冲区的更新方式可能不同,并且跨语言的效率不同。
加快此类模式速度的常用正则表达式技术是unroll-the-loop principle:在左定界符和右定界符之间的块中抓取文本。在Rust regex中,您可以使用
<!--([^>-]*(?:--?[^>-]*|[^-](?:-|>[^>-]*))*)-->
请参见regex demo(比起original regex,请参见45步与90的步)
详细信息
<!--
-左定界符([^>-]*(?:--?[^>-]*|[^-](?:-|>[^>-]*))*)
-组1:[^>-]*
-0或多个>
和-
]以外的字符>(?:--?[^>-]*|[^-](?:-|>[^>-]*))*
-0次或多次出现:--?[^>-]*
--
,可选的-
,然后是0+个除>
和-
]以外的字符|
-或[^-](?:-|>[^>-]*)
-除-
以外的任何字符,后跟-
或>
以及除>
和-
之外的0+个字符)>-->
-右定界符