# Searching and Counting

> StringZilla for C++

The view and the owning string expose `find`/`rfind` for sub-strings, single characters, and byte-sets, plus `contains`, `starts_with`, `ends_with`, and the full `find_first_of` / `find_last_of` / `find_first_not_of` / `find_last_not_of` family taking either a `byteset` or a view.
For repeated matching the view offers lazy, allocation-free ranges: `find_all(needle)` and `rfind_all(needle)`, each with `sz::include_overlaps` / `sz::exclude_overlaps` tag overloads, alongside `find_all(byteset)` and `rfind_all(byteset)`.
An empty needle matches at every offset from 0 to `size()` inclusive, so it yields `size() + 1` zero-width matches.

```cpp
#include <stringzilla/stringzilla.hpp>
namespace sz = ashvardanian::stringzilla;

int main() {
    sz::string_view_t haystack = "the quick brown fox";

    auto pos = haystack.find("quick");           // index, or sz::string_view_t::npos
    assert(pos == 4);
    assert(haystack.contains("brown"));
    assert(haystack.starts_with("the"));
    assert(haystack.ends_with("fox"));

    std::size_t words = 0;
    for (auto word : haystack.find_all(sz::whitespaces_set())) (void)word, ++words;

    auto vowels = sz::byteset_t {"aeiou", 5};
    auto first_vowel = haystack.find_first_of(vowels);
    assert(first_vowel == 2); // index of 'e'
    return 0;
}
```

The view also offers character-class predicates — `is_alpha`, `is_alnum`, `is_ascii`, `is_digit`, `is_lower`, `is_upper`, `is_space`, `is_printable`, and the general `contains_only(byteset)`.

`#include <stringzilla/stringzilla.hpp>`

## range_haystack_for

Infers how a haystack is stored inside a range-producing view.

```cpp
template <typename haystack_type_>
struct range_haystack_for
```

The range-producing functions take a forwarding reference, so the value category of the argument decides the storage. An __lvalue__ is borrowed as a non-owning view into the caller's buffer - no copy is made, and the produced slices stay comparable against iterators of the original string. An __rvalue__ is stored by value, keeping the temporary alive for as long as the range walks it.

Borrowing matters beyond the copy: a view over a copied haystack yields slices that point into that private copy, so measuring them against the caller's iterators gives meaningless offsets.

## range_needle_for

Infers how a needle is stored inside a matcher.

```cpp
template <typename view_type_,
          typename needle_type_>
struct range_needle_for
```

As with the haystack, an lvalue needle is borrowed as the haystack's view type, and an rvalue one is moved in and kept by value, which is what keeps `find_all(haystack, std::move(needle))` safe - viewing a temporary needle would leave the matcher pointing at freed memory for the whole life of the range. Raw character buffers have no `length()` member to match against, and string literals have static storage, so they are narrowed to the view type too.

## find_matches_view

A range of string slices representing the matches of a substring search.

```cpp
template <typename string_type_,
          typename matcher_type_>
class find_matches_view
```

Notes: Lifetime semantics: Stores forwarded objects, owning strings included, to keep them alive. Iterators receive lightweight views only, so iteration is safe from ownership bugs.

Notes: For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for high-performance applications where cache efficiency and register allocation matter.

Notes: Sentinel support: Supports sentinel-based iteration via `operator==(end_sentinel_t)` for efficient termination without constructing full end iterators.

Notes: Compatible with C++20 ranges, `std::string_view`, and of course, StringZilla.

Notes: Similar to a pair of `boost::algorithm::find_iterator`.

## rfind_matches_view

A range of string slices representing the matches of a __reverse-order__ substring search.

```cpp
template <typename string_type_,
          typename matcher_type_>
class rfind_matches_view
```

Notes: Lifetime semantics: Stores forwarded objects, owning strings included, to keep them alive. Iterators receive lightweight views only, so iteration is safe from ownership bugs.

Notes: For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for high-performance applications where cache efficiency and register allocation matter.

Notes: Sentinel support: Supports sentinel-based iteration via `operator==(end_sentinel_t)` for efficient termination without constructing full end iterators.

Notes: Compatible with C++20 ranges, `std::string_view`, and of course, StringZilla.

Notes: Similar to a pair of `boost::algorithm::find_iterator`.

## matcher_utf8_uncased_search

Stateful matcher driving [find_matches_view](#find_matches_view) over __case-insensitive__ UTF-8 matches.

```cpp
template <typename string_type_>
struct matcher_utf8_uncased_search
```

The uncased twin of `matcher_find:` [`sz_utf8_uncased_search_best`](https://www.unum.cloud/docs/stringzilla/c/case-folding-and-normalization.md#sz_utf8_uncased_search_best) resolves each match of the prepared [utf8_uncased_needle_t](https://www.unum.cloud/docs/stringzilla/cpp/case-folding-and-normalization.md#utf8_uncased_needle_t). Because case folding can change a match's byte length, `needle_length` reports the byte span of the __last__ match rather than the needle's own length. Matches are reported __non-overlapping__ and on codepoint boundaries, so an empty match steps over one codepoint: an empty needle matches at every boundary, the end included.

## find_all

Find all potentially __overlapping__ inclusions of a needle substring.

```cpp
template <typename haystack_type_, typename needle_type_>
find_matches_view<range_haystack_type<haystack_type_>, matcher_find<range_view_type<haystack_type_>, include_overlaps_t, range_needle_type<haystack_type_, needle_type_>>> find_all(
    haystack_type_ && h,
    needle_type_ && n,
    include_overlaps_t = {}) noexcept;
```

```cpp
template <typename haystack_type_, typename needle_type_>
find_matches_view<range_haystack_type<haystack_type_>, matcher_find<range_view_type<haystack_type_>, exclude_overlaps_t, range_needle_type<haystack_type_, needle_type_>>> find_all(
    haystack_type_ && h,
    needle_type_ && n,
    exclude_overlaps_t) noexcept;
```

Find all __non-overlapping__ inclusions of a needle substring.

Notes: An __empty__ needle matches at every offset from 0 to `size()` inclusive, yielding `size() + 1` zero-width matches.

Notes: An __empty__ needle matches at every offset from 0 to `size()` inclusive, yielding `size() + 1` zero-width matches, as each one advances the search by a byte.

## rfind_all

Find all potentially __overlapping__ inclusions of a needle substring in __reverse__ order.

```cpp
template <typename haystack_type_, typename needle_type_>
rfind_matches_view<range_haystack_type<haystack_type_>, matcher_rfind<range_view_type<haystack_type_>, include_overlaps_t, range_needle_type<haystack_type_, needle_type_>>> rfind_all(
    haystack_type_ && h,
    needle_type_ && n,
    include_overlaps_t = {}) noexcept;
```

```cpp
template <typename haystack_type_, typename needle_type_>
rfind_matches_view<range_haystack_type<haystack_type_>, matcher_rfind<range_view_type<haystack_type_>, exclude_overlaps_t, range_needle_type<haystack_type_, needle_type_>>> rfind_all(
    haystack_type_ && h,
    needle_type_ && n,
    exclude_overlaps_t) noexcept;
```

Find all __non-overlapping__ inclusions of a needle substring in __reverse__ order.

Notes: An __empty__ needle yields `size() + 1` zero-width matches, from the end to the start.

See also: [find_all](#find_all)

## find_all_characters

Find all inclusions of characters from the second string.

```cpp
template <typename haystack_type_, typename needle_type_>
find_matches_view<range_haystack_type<haystack_type_>, matcher_find_first_of<range_view_type<haystack_type_>>> find_all_characters(
    haystack_type_ && h,
    needle_type_ const & n) noexcept;
```

## rfind_all_characters

Find all inclusions of characters from the second string in __reverse__ order.

```cpp
template <typename haystack_type_, typename needle_type_>
rfind_matches_view<range_haystack_type<haystack_type_>, matcher_find_last_of<range_view_type<haystack_type_>>> rfind_all_characters(
    haystack_type_ && h,
    needle_type_ const & n) noexcept;
```

## find_all_other_characters

Find all characters except the ones in the second string.

```cpp
template <typename haystack_type_, typename needle_type_>
find_matches_view<range_haystack_type<haystack_type_>, matcher_find_first_of<range_view_type<haystack_type_>>> find_all_other_characters(
    haystack_type_ && h,
    needle_type_ const & n) noexcept;
```

## rfind_all_other_characters

Find all characters except the ones in the second string in __reverse__ order.

```cpp
template <typename haystack_type_, typename needle_type_>
rfind_matches_view<range_haystack_type<haystack_type_>, matcher_find_last_of<range_view_type<haystack_type_>>> rfind_all_other_characters(
    haystack_type_ && h,
    needle_type_ const & n) noexcept;
```

## advanced

Helper function using `std::advance` iterator and return it back.

```cpp
template <typename iterator_type, typename distance_type>
iterator_type advanced(iterator_type && it, distance_type n);
```

## range_length

Helper function using [`range_length`](#range_length) to compute the unsigned distance.

```cpp
template <typename iterator_type>
std::size_t range_length(iterator_type first, iterator_type last);
```

