如何在不克隆数据的情况下循环调用正则表达式
How to call regexes in a loop without cloning the data
我正在编写一些代码来对内容调用 N 个正则表达式,如果可能的话,我想避免一直克隆字符串,因为并非每个正则表达式实际上都是匹配的。这可能吗?
我尝试做的代码是这样的:
use std::borrow::Cow;
use regex::Regex;
fn main() {
let test = "abcde";
let regexes = vec![
(Regex::new("a").unwrap(), "b"),
(Regex::new("b").unwrap(), "c"),
(Regex::new("z").unwrap(), "-"),
];
let mut contents = Cow::Borrowed(test);
for (regex, new_value) in regexes {
contents = regex.replace_all(&contents, new_value);
}
println!("{}", contents);
}
预期结果将是 cccde
(如果有效)和两个克隆。但是为了让它工作,我必须在每次迭代中继续克隆:
fn main() {
let test = "abcde";
let regexes = vec![
(Regex::new("a").unwrap(), "b"),
(Regex::new("b").unwrap(), "c"),
(Regex::new("z").unwrap(), "-"),
];
let mut contents = test.to_string();
for (regex, new_value) in regexes {
contents = regex.replace_all(&contents, new_value).to_string();
}
println!("{}", contents);
}
然后输出 cccde
但有 3 个克隆。
有可能以某种方式避免它吗?我知道我可以调用每个正则表达式并重新绑定 return 但我无法控制可能出现的正则表达式的数量。
提前致谢!
编辑 1
对于那些想看真实代码的人:
它正在执行 O(n^2) 正则表达式操作。
从这里开始https://github.com/jaysonsantos/there-i-fixed-it/blob/ad214a27606bc595d80bb7c5968d4f80ac032e65/src/plan/executor.rs#L185-L192 and calls this https://github.com/jaysonsantos/there-i-fixed-it/blob/main/src/plan/mod.rs#L107-L115
编辑 2
这是包含已接受答案的新代码 https://github.com/jaysonsantos/there-i-fixed-it/commit/a4f5916b3e80749de269efa219b0689cb08551f2
您可以通过在替换字符串时将字符串用作字符串的持久所有者来实现,并在每次迭代时检查返回的 Cow
是否为拥有者。如果它被拥有,您就知道替换成功了,所以您将 Cow
拥有的字符串分配给循环变量。
let mut contents = test.to_owned();
for (regex, new_value) in regexes {
let new_contents = regex.replace_all(&contents, new_value);
if let Cow::Owned(new_string) = new_contents {
contents = new_string;
}
}
请注意,Rust 中的赋值默认是 'move' - 这意味着 new_string
的值被移动而不是复制到 contents
.
我正在编写一些代码来对内容调用 N 个正则表达式,如果可能的话,我想避免一直克隆字符串,因为并非每个正则表达式实际上都是匹配的。这可能吗? 我尝试做的代码是这样的:
use std::borrow::Cow;
use regex::Regex;
fn main() {
let test = "abcde";
let regexes = vec![
(Regex::new("a").unwrap(), "b"),
(Regex::new("b").unwrap(), "c"),
(Regex::new("z").unwrap(), "-"),
];
let mut contents = Cow::Borrowed(test);
for (regex, new_value) in regexes {
contents = regex.replace_all(&contents, new_value);
}
println!("{}", contents);
}
预期结果将是 cccde
(如果有效)和两个克隆。但是为了让它工作,我必须在每次迭代中继续克隆:
fn main() {
let test = "abcde";
let regexes = vec![
(Regex::new("a").unwrap(), "b"),
(Regex::new("b").unwrap(), "c"),
(Regex::new("z").unwrap(), "-"),
];
let mut contents = test.to_string();
for (regex, new_value) in regexes {
contents = regex.replace_all(&contents, new_value).to_string();
}
println!("{}", contents);
}
然后输出 cccde
但有 3 个克隆。
有可能以某种方式避免它吗?我知道我可以调用每个正则表达式并重新绑定 return 但我无法控制可能出现的正则表达式的数量。
提前致谢!
编辑 1
对于那些想看真实代码的人: 它正在执行 O(n^2) 正则表达式操作。 从这里开始https://github.com/jaysonsantos/there-i-fixed-it/blob/ad214a27606bc595d80bb7c5968d4f80ac032e65/src/plan/executor.rs#L185-L192 and calls this https://github.com/jaysonsantos/there-i-fixed-it/blob/main/src/plan/mod.rs#L107-L115
编辑 2 这是包含已接受答案的新代码 https://github.com/jaysonsantos/there-i-fixed-it/commit/a4f5916b3e80749de269efa219b0689cb08551f2
您可以通过在替换字符串时将字符串用作字符串的持久所有者来实现,并在每次迭代时检查返回的 Cow
是否为拥有者。如果它被拥有,您就知道替换成功了,所以您将 Cow
拥有的字符串分配给循环变量。
let mut contents = test.to_owned();
for (regex, new_value) in regexes {
let new_contents = regex.replace_all(&contents, new_value);
if let Cow::Owned(new_string) = new_contents {
contents = new_string;
}
}
请注意,Rust 中的赋值默认是 'move' - 这意味着 new_string
的值被移动而不是复制到 contents
.