C++ · Searching and Counting

Searching and Counting

#include <stringzilla/stringzilla.hpp> 6.0.0-rc.1 · 91a27bdd

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.

#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).

API

Types

range_haystack_forInfers how a haystack is stored inside a range-producing view.
stringzilla.hpp:505 ↗
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_forInfers how a needle is stored inside a matcher.
stringzilla.hpp:531 ↗
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_viewA range of string slices representing the matches of a substring search.
stringzilla.hpp:601 ↗
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.
  • For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for high-performance applications where cache efficiency and register allocation matter.
  • Sentinel support: Supports sentinel-based iteration via operator==(end_sentinel_t) for efficient termination without constructing full end iterators.
  • Compatible with C++20 ranges, std::string_view, and of course, StringZilla.
  • Similar to a pair of boost::algorithm::find_iterator.
rfind_matches_viewA range of string slices representing the matches of a reverse-order substring search.
stringzilla.hpp:703 ↗
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.
  • For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for high-performance applications where cache efficiency and register allocation matter.
  • Sentinel support: Supports sentinel-based iteration via operator==(end_sentinel_t) for efficient termination without constructing full end iterators.
  • Compatible with C++20 ranges, std::string_view, and of course, StringZilla.
  • Similar to a pair of boost::algorithm::find_iterator.

Functions

find_allFind all potentially overlapping inclusions of a needle substring.
stringzilla.hpp:1588 ↗
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;
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.
  • 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_allFind all potentially overlapping inclusions of a needle substring in reverse order.
stringzilla.hpp:1606 ↗
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;
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_charactersFind all inclusions of characters from the second string.
stringzilla.hpp:1655 ↗
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_charactersFind all inclusions of characters from the second string in reverse order.
stringzilla.hpp:1667 ↗
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_charactersFind all characters except the ones in the second string.
stringzilla.hpp:1679 ↗
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_charactersFind all characters except the ones in the second string in reverse order.
stringzilla.hpp:1692 ↗
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;
advancedHelper function using std::advance iterator and return it back.
stringzilla.hpp:1786 ↗
template <typename iterator_type, typename distance_type>
iterator_type advanced(iterator_type && it, distance_type n);
range_lengthHelper function using range_length to compute the unsigned distance.
stringzilla.hpp:1793 ↗
template <typename iterator_type>
std::size_t range_length(iterator_type first, iterator_type last);