首页 > 解决方案 > 如何使用 RegexSet 执行替换?

问题描述

给定一个配置文件,它指定了几个(可能几十个)正则表达式,例如:

("2018")
authors[ ]*=[ ]*(.*)

我想遍历输入流(逐行)并替换所有捕获(在此示例中,“2018”的所有实例和作者姓名)。替换取决于捕获,因此年份将替换为“(年份)”,作者姓名替换为“(作者)”。

我试过的

extern crate regex; // 1.1.5

use regex::Regex;
use regex::RegexSet;
use std::process;
use std::{
    fs::File,
    io,
    io::{prelude::*, BufReader},
    path::PathBuf,
};

fn main() {
    let contents = read_to_array("config.conf");
    println!("{:?}", contents);

    let set = RegexSet::new(&contents).unwrap(); // FIXME: this panics if there is an invalid regex
    println!("{:?}", set);

    let mut regexs: Vec<Regex> = Vec::new();
    for line in contents {
        let re = Regex::new(&line).unwrap(); // should not panic because we parsed Regexes above already
        regexs.push(re);
    }

    read(set, regexs);
}

fn read_to_array(filename: &str) -> Vec<String> {
    let file = File::open(filename).expect("no such file");
    let buf = BufReader::new(file);
    buf.lines()
        .map(|l| l.expect("Could not parse line"))
        .collect()
}

fn read(set: RegexSet, regexs: Vec<Regex>) {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let l = line.unwrap();
        let mut r = l.to_string();
        println!("line: {}", l);
        for idx in set.matches(&l).into_iter() {
            println!(
                "matches: {:?} - {:?} = {:?}",
                idx,
                set.patterns()[idx],
                regexs[idx]
            );
            for caps in regexs[idx].captures_iter(&l) {
                println!("captures: {:?}", caps);
                for c in caps.iter() {
                    println!("cap: {:?}", c);
                }
                r = regexs[idx].replace_all(&r, "xxx").to_string();
                println!("result: {:?}", r);
            }
        }
        println!("new line: {}", r);
    }
}

操场

这需要regex = "1"在 Cargo.toml 中,需要在config.conf当前目录中命名的配置文件,以及通过标准输入管道输入的数据 - Cargo.toml 可以很好地用于测试目的。

什么不起作用

RegexSet没有给我捕获,所以我用它来有效地确定我是否有匹配,然后再次匹配以进行替换。这让我觉得非常笨重,但这是我让它工作的唯一方法。

其次,替换总是替换整个匹配,而不仅仅是捕获的部分。那是我不明白的事情,它不适合正则表达式箱的文档。

第三,遍历捕获 - 这可能是#2的原因 - 总是给我索引0处的整个匹配,我想跳过它。Rust 中是否有类似“迭代这个,但跳过第一个元素”的东西?

标签: regexrust

解决方案


推荐阅读