Skip to content

str methods

Level: reference · for working programmers

One line: One page per method on the str primitive — all 83 that stable Rust 1.98 exposes — each with the signature, what it actually does, the trap it is usually involved in, and a program whose printed output is checked by CI.

These pages are a reference, not a course. If you have not met String and &str yet, read the strings arc first — it explains the owner-and-view pattern that makes half of this list make sense. Come back here when you know which method you want and need to know how it behaves at the edges.

Every page has the same shape: a one-line summary, the signature, the stability line, the prose, then a complete runnable program and its verified output. Nothing on any of these pages is hand-typed output — tools/run_examples.py compiles each example, runs it, and fails the build if what the page shows is not what the program printed.

Where a page prints a table of inputs and results, the input column is built with format!("{s:?}") and then padded as a plain String. The obvious spelling, {s:<7?}, compiles and silently does nothing: width and alignment reach every Debug impl as Formatter state, and the one for &str never reads it — so the arrows do not line up and nothing warns you. That trap has its own section on the Debug and Display page.

The signature block is a text fence rather than a rust one on purpose: a bare pub fn … is not something you can paste into a file, and the house rule is that the first rust block on a page must compile. The first rust block here is always the real example.

The pattern argument

Twenty-odd methods below take a P: Pattern, and that one trait is why searching, splitting, trimming and replacing all accept the same four shapes:

shape example matches worked example
char s.split(',') that one character split
&str s.split(", ") that exact substring split_once
&[char] s.split(&['-', '_'][..]) any one of those characters trim_matches
FnMut(char) -> bool s.split(char::is_numeric) any character the closure approves matches

The last column is a page whose program uses that shape and is compiled and run by CI, so you can read the row working rather than take it on trust — and the four pages are four different methods, which is the trait's whole point. For all four shapes in one program, contains calls it four times, one line per shape.

&[char] is the shape that stays unfamiliar: of the 83 examples here only three use it — contains, split and trim_matches. The [..] on it is a habit rather than a requirement, and worth not copying into new code: Pattern is implemented for [char; N] and &[char; N] too, so s.split(['-', '_']) compiles and does the same thing.

A &str pattern is never accepted where the method has to search backwards from both ends at oncetrim_matches is the one that refuses it. Chain the two one-sided methods there instead.

The two panics

Almost every panic in this list is one of two, and both are about byte offsets:

  • out of range — the offset is past len()
  • inside a character — the offset is not a character boundary, because len() counts bytes and a char can occupy up to four of them

is_char_boundary is the test, get and the _checked methods return Option instead of panicking, and floor_char_boundary repairs an offset rather than refusing it.


How long is it, and what is it made of

method what it does
len The byte count — not the character count
is_empty len() == 0, spelled so it reads
as_bytes The UTF-8 bytes as &[u8], free
bytes The same bytes as an iterator of u8
chars An iterator of char — Unicode scalars, not graphemes
char_indices Characters with the byte offsets you can slice at
lines Split on \n, dropping a trailing \r and the final empty line
is_ascii Whether every byte is under 128 — the ascii family's precondition

Is it there, and where

Every method here takes a pattern.

method what it does
contains Whether the pattern occurs anywhere
starts_with Whether it occurs at the front
ends_with Whether it occurs at the back
find The byte offset of the first match, as Option<usize>
rfind The byte offset of the last match
matches The matched substrings themselves
rmatches The same, yielded back to front
match_indices Each match with its byte offset
rmatch_indices The same, back to front — the order in-place edits need
substr_range Where a sub-slice sits in this string — identity, not search

Cutting it up

Splits report the gaps between matches, so n matches give n+1 pieces.

method what it does
split The pieces between the matches — empties included
rsplit The same pieces, last to first
splitn At most n pieces; the remainder stays whole
rsplitn The same limit, applied from the right
split_once Exactly two pieces at the first match, or None
rsplit_once Exactly two pieces at the last match, or None
split_terminator Drops a trailing empty piece
rsplit_terminator The same rule, iterated from the right
split_inclusive Keeps the separator on the piece it ended
split_whitespace Collapses runs of whitespace — the editorial split, for prose
split_ascii_whitespace The same, ASCII-only and faster
split_at Two halves at a byte offset — panics off a boundary
split_at_checked The same cut, returning Option
split_at_mut Two mutable halves, which plain borrowing cannot give
split_at_mut_checked The mutable cut, returning Option

Taking things off the ends

method what it does
trim Unicode whitespace off both ends, borrowed
trim_start The front only
trim_end The back only — what to call on a line you just read
trim_matches A pattern off both ends, repeatedly
trim_start_matches Repeatedly, at the front — accepts a &str
trim_end_matches Repeatedly, at the back
trim_ascii ASCII whitespace only, and const
trim_ascii_start The front only, const
trim_ascii_end The back only, const
strip_prefix Removes it once and tells you whether it was there
strip_suffix The same at the back
strip_circumfix Both ends at once — Some only if both matched

Changing the case

The ascii half is length-preserving; the Unicode half is not.

method what it does
to_lowercase Full Unicode — context-sensitive, and can change length
to_uppercase Full Unicode — ß becomes SS, so it does not round-trip
to_ascii_lowercase AZ only, everything else untouched
to_ascii_uppercase az only — no ß expansion
make_ascii_lowercase The same, in place, no allocation
make_ascii_uppercase The same, in place
eq_ignore_ascii_case Case-insensitive comparison with no allocation at all

Making a new string out of this one

Everything here allocates — a str cannot change its own length.

method what it does
replace Every occurrence of a pattern
replacen The first n occurrences
repeat n copies, allocated once
parse Into any FromStr type — and it does not trim first
into_string Box<str>String, without copying
into_boxed_bytes Box<str>Box<[u8]>, without copying

Byte offsets, and the panics they cause

The two failure modes are always the same: out of range, or inside a character.

method what it does
get Slicing that returns Option instead of panicking
get_mut The same, mutable
is_char_boundary Whether an offset is a legal slice endpoint
floor_char_boundary Nudge a bad offset down — the safe byte-budget truncation
ceil_char_boundary Nudge it up — can exceed the budget, and panics past the end

Bytes in, bytes out

method what it does
from_utf8 Validate &[u8] into &str, borrowing
from_utf8_mut The same, mutable
encode_utf16 Out to UTF-16 code units — surrogate pairs make a third length
escape_debug As {:?} prints it — printable non-ASCII stays readable
escape_default Escaped to pure ASCII
escape_unicode Every character as \u{...}, no exceptions
as_ptr The raw address — for FFI, and not NUL-terminated
as_mut_ptr The writable raw address

unsafe — the checks removed

Each one trades a cheap check for an obligation you now carry.

method what it does
as_bytes_mut Writable bytes — must still be valid UTF-8 when the borrow ends
get_unchecked get with no bounds or boundary check
get_unchecked_mut The mutable version
from_utf8_unchecked &[u8]&str with no validation
from_utf8_unchecked_mut The mutable version — unvalidated and writable

Deprecated, and still compiling

Here because you will meet them in older code.

method what it does
trim_left trim_start
trim_right trim_end
trim_left_matches trim_start_matches
trim_right_matches trim_end_matches
lines_any lines
slice_unchecked get_unchecked
slice_mut_unchecked get_unchecked_mut

Where to go next

Po polsku

Ta strona jest spisem, a nie lekcją: 83 metody prymitywu str, każda na własnej stronie, z sygnaturą, pułapką i programem, który CI kompiluje i uruchamia. Jeśli podział na String (właściciel, łańcuch znaków na stercie) i &str (wycinek łańcucha, sam podgląd) jeszcze się nie ułożył, zacznij od strony o łańcuchach znaków — połowa tej listy robi się zrozumiała dopiero wtedy.

Argument nazywany tu wzorcem (P: Pattern) potrafi zmylić, bo to nie jest wyrażenie regularne — biblioteka standardowa Rusta nie ma regexów w ogóle, od tego jest crate regex. Pattern przyjmuje cztery kształty: pojedynczy char, dosłowny podłańcuch &str, tablicę &[char] (pasuje którykolwiek z wymienionych znaków) i domknięcie FnMut(char) -> bool. Dlatego split, find, trim_matches i replace biorą dokładnie to samo, i dlatego jedna nauczona rzecz obsługuje dwadzieścia metod.

Reszta strony to dwie pułapki i obie uderzają w polskiego czytelnika mocniej niż w anglojęzycznego, bo nasz tekst nie jest ASCII. Pierwsza: wszystkie przesunięcia są bajtowe. "żółw".len() to 7, a nie 4 — ż, ó i ł zajmują w UTF-8 po dwa bajty — więc &s[0..1] nie zwróci „ż”, tylko spanikuje komunikatem end byte index 1 is not a char boundary; it is inside 'ż' (bytes 0..2 of string). Liczbę znaków daje chars().count(), pozycję do cięcia char_indices, a is_char_boundary, get i floor_char_boundary to trzy sposoby na to, żeby zamiast paniki dostać odpowiedź.

Druga: mnóstwo metod z powyższych tabel ma bliźniaka z ascii w nazwie i dla polskiego tekstu ta wersja bywa cicho zła — nie wywala się, po prostu nic nie robi:

  • to_ascii_uppercase zostawia "żółw" bez zmian; wielkie litery daje dopiero to_uppercase"ŻÓŁW"
  • eq_ignore_ascii_case uzna "Łódź" i "łódź" za różne łańcuchy
  • trim_ascii i split_ascii_whitespace nie widzą twardej spacji U+00A0, którą polska typografia stawia po jednoliterowych wyrazach „w”, „z”, „i”, „a”

Wersje bez ascii są wolniejsze i czasem alokują, ale to one rozumieją polski. Po ascii sięgaj świadomie — do nagłówków HTTP, protokołów, identyfikatorów — a nie do tekstu, który ktoś napisał.

Szukaj po polsku: metody łańcuchów znaków · przesunięcie bajtowe a znak · rust str methods · rust Pattern trait split · rust not a char boundary