Skip to content

str::match_indices

str methods · Strings

Level: reference · for working programmers

One line: Every match paired with the byte offset it starts at — (usize, &str), and the offsets are safe to slice with.

pub fn match_indices<P: Pattern>(&self, pat: P) -> MatchIndices<'_, P>

Stable since 1.5.0.

find gives you the first match's offset; this gives you all of them. It is the tool for building a highlighter, a replace-with-context, or any job that needs to know where each hit was rather than just how many there were.

The offset is the start of the match; the end is i + m.len(), so &s[i..i + m.len()] is the match itself and the text between hits is what split would have given you.

Non-overlapping and left to right, exactly like matches.

Example

str_match_indices.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    let s = "the rain in spain";

    for (i, m) in s.match_indices("in") {
        println!("byte {i:>2}: {m:?}  ...{:?}", &s[i..(i + m.len() + 2).min(s.len())]);
    }

    // Offsets plus lengths reconstruct both the matches and the gaps.
    let hits: Vec<(usize, &str)> = s.match_indices("in").collect();
    println!("{hits:?}");
    println!("{:?}", s.split("in").collect::<Vec<&str>>());

    // Marking up every hit.
    let mut out = String::new();
    let mut last = 0;
    for (i, m) in s.match_indices("in") {
        out.push_str(&s[last..i]);
        out.push('[');
        out.push_str(m);
        out.push(']');
        last = i + m.len();
    }
    out.push_str(&s[last..]);
    println!("{out}");
}

Verified output of str_match_indices.rs — regenerated by tools/run_examples.py, never hand-typed.

byte  6: "in"  ..."in i"
byte  9: "in"  ..."in s"
byte 15: "in"  ..."in"
[(6, "in"), (9, "in"), (15, "in")]
["the ra", " ", " spa", ""]
the ra[in] [in] spa[in]

See also

str::match_indices in the standard library ↗

Po polsku

match_indices zwraca pary (usize, &str), a ta liczba to przesunięcie w bajtach, nie numer znaku — różnica, której w Pythonie nie ma i o którą w polskim tekście łatwo się potknąć: w "żaba żaba" drugie wystąpienie zaczyna się na bajcie 6, choć na znaku 5, bo ż zajmuje w UTF-8 dwa bajty. To nie usterka, tylko sedno metody: offset pochodzi z prawdziwego dopasowania, więc z definicji leży na granicy znaku i wycinek &s[i..i + m.len()] nigdy nie wywoła paniki — inaczej niż indeks policzony na piechotę. Gdy chcesz pokazać człowiekowi „znaleziono na pozycji N", przelicz to osobno przez s[..i].chars().count(); a jeżeli interesuje cię tekst pomiędzy trafieniami, to dokładnie to, co zwróciłby split() z tym samym wzorcem.

Szukaj po polsku: pozycja znaku a pozycja bajtu · wyszukiwanie wszystkich wystąpień · przesunięcie w bajtach · rust match_indices byte offset · rust find all occurrences in string