Как выполнить замену с помощью RegexSet? - PullRequest
0 голосов
/ 22 мая 2019

Имеется файл конфигурации, который задает несколько (возможно, десятки) регулярных выражений, например:

("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);
    }
}

1012 * площадка *

Для этого требуется regex = "1" в Cargo.toml, ожидается файл конфигурации с именем config.conf в текущем каталоге и данные для манипуляции, переданные через stdin - Cargo.toml хорошо работает в целях тестирования.

Что не работает

RegexSet не дает мне снимков, поэтому я использую его, чтобы выяснить, есть ли у меня совпадение, а затем сопоставить снова для замены. Это кажется мне неуклюжим, но это единственный способ заставить его работать.

Во-вторых, замена всегда заменяет весь матч, а не только захваченную часть. Это то, что я не понимаю, и это не соответствует документации регулярных выражений.

В-третьих, повторение перехватов - и это может быть причиной № 2 - всегда дает мне полное совпадение с индексом 0, которое я хотел бы пропустить. Есть ли что-то вроде «перебрать это, но пропустить первый элемент» в Rust?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...