我正在尝试删除字符串中的所有括号。不用太费劲,我只是做一个简单的regexp替换(即,问题不是特别要摆脱嵌套括号的任意级别,而是可以随意在注释中建议一种更好的方法) )。
use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = "Text (with some (nested) parentheses)!";
let re = Regex::new(r"\([^()]*\)")?;
let output = re.replace_all(&input, "");
let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// ...
assert_eq!("Text !", output);
println!("Works!");
Ok(())
}
因为我不知道括号的嵌套方式,所以我需要循环进行替换,而不是重复“足够多次”。但是,创建循环会创建一个新的作用域,而这正是我在借阅检查器的讨论中遇到的僵局。
显示我要在循环中尝试做的最简单的情况是:
let mut output = re.replace_all(&input, "");
while re.is_match(&output) {
output = re.replace_all(&output, "");
}
但是由于我要分配给借来的变量而无法完成操作
error[E0506]: cannot assign to `output` because it is borrowed
--> src/main.rs:9:9
|
9 | output = re.replace_all(&output, "");
| ^^^^^^ ------- borrow of `output` occurs here
| |
| assignment to borrowed `output` occurs here
| borrow later used here
理想情况下,我想做的是创建具有相同名称的新变量绑定,但是使用let output =
会遮盖外部变量绑定,因此循环将无限循环。
无论我创建什么内部或外部临时变量,我都无法使它做我想要的事情。我还尝试使用re.replace_all()
返回Cow
的事实,并尝试在几个地方使用.to_owned()
和.to_string()
,但这都没有帮助。
答案 0 :(得分:1)
re.replace_all()
返回Cow
这是问题的根源。编译器知道返回值可能引用output
,但也会替换 output
,导致output
立即被丢弃。如果允许这样做,则引用将指向未分配的内存,从而导致内存不安全。
解决方案是完全避免借款。
使用
.to_owned()
to_owned
上的 Cow
仅返回相同的Cow
。也许您是说into_owned
?
let mut output = re.replace_all(&input, "").into_owned();
while re.is_match(&output) {
output = re.replace_all(&output, "").into_owned();
}
和
.to_string()
在几个地方
这同样有效:
let mut output = re.replace_all(&input, "").to_string();
while re.is_match(&output) {
output = re.replace_all(&output, "").to_string();
}
很遗憾您没有展示出解决问题的实际尝试,我们本可以帮助您了解为什么它们不起作用。
答案 1 :(得分:0)
Shepmaster 的回答有效,但没有达到应有的效率。 Cow
类型的一个微妙属性是,通过检查它,我们可以确定字符串是否被修改,如果没有,则跳过工作。
由于 Rust 类型系统的限制,如果该值未修改,则 Cow::into_owned()
进行复制。 (修改的值的Cow::into_owned()
不会复制)。 (into_owned documentation)
在您的用例中,我们可以检测未修改的 Cow
-- Cow::Borrowed
-- 并跳过 into_owned()
。
while re.is_match(&output).unwrap() {
match re.replace_all(&output, "") {
// Unmodified -- skip copy
Cow::Borrowed(_) => {}
// replace_all() returned a new value that we already own
Cow::Owned(new) => output = new,
}
}
但我们可以走得更远。同时调用 is_match()
和 replace_all()
表示模式匹配两次。凭借我们对 Cow
的新知识,我们可以对其进行优化:
// Cow::Owned is returned when the string was modified.
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = new;
}