Daxia Blog
Uncategorized | Rust | WebUI | FHIR | Javascript | KB

字符串中的变量替换

有一个Map,里面存储了a=value1, b=value2, 现在有一个字符串,里面包含了形如${a}的占位符,现在需要将Map中的值来替换字符串中的变量占位符。

首先,你需要引入 regex依赖:

cargo add regex

可以直接使用regexreplace_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!"*

这个实现是线程安全的,并且性能较好。

About Daxia
我是一名独立开发者,国家工信部认证高级系统架构设计师,在健康信息化领域与许多组织合作。具备大型卫生信息化平台产品架构、设计和开发的能力,从事软件研发、服务咨询、解决方案、行业标准编著相关工作。
我对健康信息化非常感兴趣,尤其是与HL7和FHIR标准的健康互操作性。我是HL7中国委员会成员,从事FHIR培训讲师和FHIR测评现场指导。
我还是FHIR Chi的作者,这是一款用于FHIR测评的工具。