Rust regex replace_all比PHP regex preg_replace_callback慢,如何优化?

问题描述 投票:1回答:1

在下面的示例中,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: &regex::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

谢谢!

php regex performance optimization rust
1个回答
0
投票

这可能是由于在Rust regex中实现了惰性模式扩展。请注意,懒惰的(.*?)模式的工作方式如下:首先将其跳过,然后正则表达式引擎将尝试后续的模式,即-->。如果-->之后不存在<!--,则正则表达式引擎返回(.*?),在<--之后获取下一个字符,并将其放入第1组的单独的内存缓冲区中,然后再次重试以与之匹配-->失败后返回,将char与.*?匹配,并修改组1内存缓冲区,依此类推。因此,第1组内存缓冲区的更新方式可能不同,并且跨语言的效率不同。

加快此类模式速度的常用正则表达式技术是unroll-the-loop principle:在左定界符和右定界符之间的块中抓取文本。在Rust regex中,您可以使用

 <!--([^>-]*(?:--?[^>-]*|[^-](?:-|>[^>-]*))*)-->

请参见regex demo(比起original regex,请参见45步与90的步)

详细信息

  • <!---左定界符
  • ([^>-]*(?:--?[^>-]*|[^-](?:-|>[^>-]*))*)-组1:
    • [[^>-]*-0或多个>-]以外的字符>
    • (?:--?[^>-]*|[^-](?:-|>[^>-]*))*-0次或多次出现:
      • [--?[^>-]*--,可选的-,然后是0+个除>-]以外的字符
      • |-或
      • [[^-](?:-|>[^>-]*)-除-以外的任何字符,后跟->以及除>-之外的0+个字符)>
  • -->-右定界符
© www.soinside.com 2019 - 2024. All rights reserved.