Regex: есть ли для этого один лайнер?
Я хочу как можно быстрее выполнить поиск в нескольких больших текстовых файлах (200 МБ каждый). Я использую инструмент командной строки ripgrep и хочу вызвать его только один раз.
В следующей строке:
***foo***bar***baz***foo***bar***baz
(***
обозначает другой тип и количество символов.)
Я хочу соответствовать baz
, но только если он следует за первым появлением foo***bar***
Так что в ***foo***bar***baz***foo***bar***baz
это соответствует первому baz
И в ***foo***bar***qux***foo***bar***baz
это не должно совпадать.
Я пробовал несколько решений, но это не сработало. Можно ли это сделать с помощью одного регулярного выражения?
1 ответ
Я почти уверен, что в этом случае регулярное выражение излишне. Простая серияfind
может выполнять работу:
fn find_baz(input: &str) -> Option<usize> {
const FOO: &str = "foo";
const BAR: &str = "bar";
// 1: we find the occurrences of "foo", "bar" and "baz":
let foo = input.find(FOO)?;
let bar = input[foo..].find(BAR).map(|i| i + foo)?;
let baz = input[bar..].find("baz").map(|i| i + bar)?;
// 2: we verify that there is no other "foo" and "bar" between:
input[bar..baz]
.find(FOO)
.map(|i| i + bar)
.and_then(|foo| input[foo..baz].find(BAR))
.xor(Some(baz))
}
#[test]
fn found_it() {
assert_eq!(Some(15), find_baz("***foo***bar***baz***foo***bar***baz"));
}
#[test]
fn found_it_2() {
assert_eq!(Some(27), find_baz("***foo***bar***qux***foo***baz"));
}
#[test]
fn not_found() {
assert_eq!(None, find_baz("***foo***bar***qux***foo***bar***baz"));
}
#[test]
fn not_found_2() {
assert_eq!(None, find_baz("***foo***bar***qux***foo***"));
}