Имеется файл конфигурации, который задает несколько (возможно, десятки) регулярных выражений, например:
("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?