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***"));
}
Другие вопросы по тегам