字符串中的变量替换
有一个Map,里面存储了a=value1, b=value2, 现在有一个字符串,里面包含了形如${a}的占位符,现在需要将Map
中的值来替换字符串中的变量占位符。
首先,你需要引入 regex
依赖:
cargo add regex
可以直接使用regex
的replace_all()
方法来进行替换,将形如${a}
的变量值替换为Map
中的对应值:
use regex::{Captures, Regex};
fn replace_placeholder(url: &String, values: &HashMap<String, String>) -> String {
let re = Regex::new(r"\$\{([a-z|A-Z|0-9]+)\}").unwrap();
let new = re.replace_all(url, |caps: &Captures| {
// 获取占位符中的键名 (去掉 ${} 后的内容)
let key = &caps[1];
// 从 HashMap 中查找对应的值
values.get(key)
.map(|s| s.as_str())
.unwrap_or(&caps[0])
}
}).into_owned()
}
这个实现有以下特点:
- 使用正则表达式来匹配
${key}
格式的占位符 - 如果在
HashMap
中找不到对应的值,会保留原始的占位符
如果期望在 HashMap
中找不到对应的值时抛出异常,就不能直接使用上述的便捷方法了。这时就需要仿照该函数重新实现replace_all()
以支持异常处理:
use regex::{Captures, Regex};
fn replace_all<E>(
re: &Regex,
haystack: &str,
replacement: impl Fn(&Captures) -> Result<String, E>,
) -> Result<String, E> {
let mut new = String::with_capacity(haystack.len());
let mut last_match = 0;
for caps in re.captures_iter(haystack) {
let m = caps.get(0).unwrap();
new.push_str(&haystack[last_match..m.start()]);
new.push_str(&replacement(&caps)?);
last_match = m.end();
}
new.push_str(&haystack[last_match..]);
Ok(new)
}
重新调整调用函数,代码如下:
fn replace_placeholder(url: &String, values: &HashMap<String, String>) -> Result<String> {
let re = Regex::new(r"\$\{([a-z|A-Z|0-9]+)\}").unwrap();
let replacement = |caps: &Captures| -> Result<String> {
// 获取占位符中的键名 (去掉 ${} 后的内容)
let key = &caps[1];
// 从 HashMap 中查找对应的值
match values.get(key) {
Some(v) => Ok(v.clone()),
None => Err(AppError::engine(format!("未在Map中找到变量[{}]", key)))
}
};
// 使用正则表达式替换所有匹配项
let new = replace_all(&re, &script, &replacement);
Ok(new)
}
使用示例:
let mut values = HashMap::new();
values.insert("a".to_string(), "value1".to_string());
values.insert("b".to_string(), "value2".to_string());
let template = "Hello ${a}, welcome to ${b}!";
let result = replace_placeholders(template, &values);
// 期望结果: "Hello value1, welcome to value2!"*
这个实现是线程安全的,并且性能较好。