Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/algorithm/ranges/find end"

From cppreference.com
< cpp‎ | algorithm‎ | ranges
( Possible implementation: reimplemented as a niebloid)
m (fmt)
 
(17 intermediate revisions by 3 users not shown)
Line 2: Line 2:
 
{{cpp/algorithm/ranges/navbar}}
 
{{cpp/algorithm/ranges/navbar}}
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl header | algorithm}}
+
{{dcl header|algorithm}}
 
{{dcl h|Call signature}}
 
{{dcl h|Call signature}}
{{dcl | num=1 | since=c++20 |1=
+
{{dcl|num=1|since=c++20|1=
template<std::forward_­iterator I1, std::sentinel_­for<I1> S1,
+
template< std::forward_iterator I1, std::sentinel_for<I1> S1,
        std::forward_­iterator I2, std::sentinel_­for<I2> S2,
+
          std::forward_iterator I2, std::sentinel_for<I2> S2,
        class Pred = ranges::equal_to,
+
          class Pred = ranges::equal_to,
        class Proj1 = std::identity, class Proj2 = std::identity>
+
          class Proj1 = std::identity,
  requires std::indirectly_­comparable<I1, I2, Pred, Proj1, Proj2>
+
          class Proj2 = std::identity >
  constexpr ranges::subrange<I1>
+
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
     ranges::find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
+
constexpr ranges::subrange<I1>
                    Proj1 proj1 = {}, Proj2 proj2 = {});
+
     find_end( I1 first1, S1 last1, I2 first2, S2 last2,
 +
              Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 
}}
 
}}
{{dcl | num=2 | since=c++20 |1=
+
{{dcl|num=2|since=c++20|1=
template<std::forward_­range R1, std::forward_­range R2,
+
template< ranges::forward_range R1, ranges::forward_range R2,
        class Pred = ranges::equal_to,
+
          class Pred = ranges::equal_to,
        class Proj1 = std::identity, class Proj2 = std::identity>
+
          class Proj1 = std::identity,
  requires std::indirectly_­comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
+
          class Proj2 = std::identity >
                                      Pred, Proj1, Proj2>
+
requires std::indirectly_comparable<ranges::iterator_t<R1>,
  constexpr ranges::borrowed_subrange_t<R1>
+
                                    ranges::iterator_t<R2>,
     ranges::find_end(R1&& r1, R2&& r2, Pred pred = {},
+
                                    Pred, Proj1, Proj2>
                    Proj1 proj1 = {}, Proj2 proj2 = {});
+
constexpr ranges::borrowed_subrange_t<R1>
 +
     find_end( R1&& r1, R2&& r2, Pred pred = {},
 +
              Proj1 proj1 = {}, Proj2 proj2 = {} );
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
@1@ Searches for the '''last''' occurrence of the sequence {{tt|[first2, last2)}} in the range {{tt|[first1, last1)}}, after projection with {{c|proj1}} and {{c|proj2}}).
+
@1@ Searches for the ''last'' occurrence of the sequence {{range|first2|last2}} in the range {{range|first1|last1}}, after projection with {{c|proj1}} and {{c|proj2}} respectively. The projected elements are compared using the binary predicate {{c|pred}}.
  
@2@ Same as {{v|1}}, but uses {{tt|r1}} as the first source range and {{tt|r2}} as the second source range, as if using {{c|ranges::begin(r1)}} as {{tt|first1}}, {{c|ranges::end(r1)}} as {{tt|last1}}, {{c|ranges::begin(r2)}} as {{tt|first2}}, and {{c|ranges::end(r2)}} as {{tt|last2}}.
+
@2@ Same as {{v|1}}, but uses {{c|r1}} as the first source range and {{c|r2}} as the second source range, as if using {{c|ranges::begin(r1)}} as {{c|first1}}, {{c|ranges::end(r1)}} as {{c|last1}}, {{c|ranges::begin(r2)}} as {{c|first2}}, and {{c|ranges::end(r2)}} as {{c|last2}}.
  
 
{{cpp/ranges/niebloid}}
 
{{cpp/ranges/niebloid}}
Line 34: Line 37:
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | first1, last1 | the range of elements to examine (aka ''haystack'')}}
+
{{par|first1, last1|the range of elements to examine (aka ''haystack'')}}
{{par | first2, last2 | the range of elements to search for (aka ''needle'')}}
+
{{par|first2, last2|the range of elements to search for (aka ''needle'')}}
{{par | r1 | the range of elements to examine (aka ''haystack'')}}
+
{{par|r1|the range of elements to examine (aka ''haystack'')}}
{{par | r2 | the range of elements to search for (aka ''needle'')}}
+
{{par|r2|the range of elements to search for (aka ''needle'')}}
{{par | pred | binary predicate to compare the elements}}
+
{{par|pred|binary predicate to compare the elements}}
{{par | proj1 | projection to apply to the elements in the first range}}
+
{{par|proj1|projection to apply to the elements in the first range}}
{{par | proj2 | projection to apply to the elements in the second range}}
+
{{par|proj2|projection to apply to the elements in the second range}}
 
{{par end}}
 
{{par end}}
  
 
===Return value===
 
===Return value===
@1@ {{c|ranges::subrange<I1>}} object initialized with expression <code>{i, i + (i == last1 ? 0 : last2 - first2)}</code> that is the last occurrence of the sequence {{tt|[first2, last2)}} in range {{tt|[first1, last1)}} (after projections with {{c|proj1}} and {{c|proj2}}). If {{tt|[first2, last2)}} is empty or if no such sequence is found, the returned object is effectivelly intialized with {{tt|{last1, last1}}}.
+
@1@ {{c|ranges::subrange<I1>{} }} value initialized with expression {{c|1={i, i + (i == last1 ? 0 : ranges::distance(first2, last2))} }} that denotes the last occurrence of the sequence {{range|first2|last2}} in range {{range|first1|last1}} (after projections with {{c|proj1}} and {{c|proj2}}). If {{range|first2|last2}} is empty or if no such sequence is found, the return value is effectively initialized with {{c|{last1, last1}<!---->}}.
@2@ same as {{v|1}} but the returned object is {{c|ranges::borrowed_subrange_t<R1>}}.
+
@2@ Same as {{v|1}}, except that the return type is {{c|ranges::borrowed_subrange_t<R1>}}.
  
 
===Complexity===
 
===Complexity===
At most {{tt|S*(N-S+1)}} applications of the corresponding predicate and any projections, where {{c|S {{=}} last2 - first2}} and {{c|N {{=}} last1 - first1}} for {{v|1}}, or {{c|S {{=}} ranges::size(r2)}} and {{c|N {{=}} ranges::size(r1)}} for {{v|2}}.
+
At most {{mathjax-or|\(\scriptsize S\cdot(N-S+1)\)|S&middot;(N-S+1)}} applications of the corresponding predicate and each projection, where {{mathjax-or|\(\scriptsize S\)|S}} is {{c|ranges::distance(first2, last2)}} and {{mathjax-or|\(\scriptsize N\)|N}} is {{c|ranges::distance(first1, last1)}} for {{v|1}}, or {{mathjax-or|\(\scriptsize S\)|S}} is {{c|ranges::distance(r2)}} and {{mathjax-or|\(\scriptsize N\)|N}} is {{c|ranges::distance(r1)}} for {{v|2}}.
  
=== Notes ===
+
===Notes===
The implementations can improve the effciency of the search if the input iterators model {{c|std::bidirectional_­iterator}} by searching from the end towards the begin. This hovewer does not improve the theoretical complexity of the worst case.
+
An implementation can improve efficiency of the search if the input iterators model {{c|std::bidirectional_iterator}} by searching from the end towards the begin. Modelling the {{c|std::random_access_iterator}} may improve the comparison speed. All this however does not change the theoretical complexity of the worst case.
  
 
===Possible implementation===
 
===Possible implementation===
{{eq fun| 1=
+
{{eq fun|1=
struct find_end_fn {
+
struct find_end_fn
 
+
{
  template<std::forward_­iterator I1, std::sentinel_­for<I1> S1,
+
    template<std::forward_iterator I1, std::sentinel_for<I1> S1,
          std::forward_­iterator I2, std::sentinel_­for<I2> S2,
+
            std::forward_iterator I2, std::sentinel_for<I2> S2,
          class Pred = ranges::equal_to,
+
            class Pred = ranges::equal_to,
          class Proj1 = std::identity, class Proj2 = std::identity>
+
            class Proj1 = std::identity, class Proj2 = std::identity>
     requires std::indirectly_­comparable<I1, I2, Pred, Proj1, Proj2>
+
     requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr ranges::subrange<I1>
+
    constexpr ranges::subrange<I1>
 
         operator()(I1 first1, S1 last1,
 
         operator()(I1 first1, S1 last1,
 
                   I2 first2, S2 last2, Pred pred = {},
 
                   I2 first2, S2 last2, Pred pred = {},
 
                   Proj1 proj1 = {}, Proj2 proj2 = {}) const
 
                   Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
+
    {
      if (first2 == last2) {
+
        if (first2 == last2)
          const auto last_it = std::next(first1, last1);
+
        {
          return {last_it, last_it};
+
            auto last_it = ranges::next(first1, last1);
      }
+
            return {last_it, last_it};
      auto result = std::ranges::search(
+
        }
        std::move(first1), last1, first2, last2, pred, proj1, proj2);
+
        auto result = ranges::search(
 +
            std::move(first1), last1, first2, last2, pred, proj1, proj2);
  
      if (result.empty()) return result;
+
        if (result.empty())
 
+
             return result;
      for (;;) {
+
          auto new_result = std::ranges::search(
+
             std::next(result.begin()), last1, first2, last2, pred, proj1, proj2);
+
          if (new_result.empty())
+
              return result;
+
          else
+
              result = std::move(new_result);
+
      }
+
  }
+
  
  template<std::forward_­range R1, std::forward_­range R2,
+
        for (;;)
        class Pred = ranges::equal_to,
+
        {
        class Proj1 = std::identity, class Proj2 = std::identity>
+
            auto new_result = ranges::search(
  requires std::indirectly_­comparable<ranges::iterator_t<R1>,
+
                std::next(result.begin()), last1, first2, last2, pred, proj1, proj2);
                                      ranges::iterator_t<R2>,
+
            if (new_result.empty())
                                      Pred, Proj1, Proj2>
+
                return result;
  constexpr ranges::borrowed_subrange_t<R1>
+
            else
    operator()(R1&& r1, R2&& r2, Pred pred = {},
+
                result = std::move(new_result);
              Proj1 proj1 = {}, Proj2 proj2 = {}) const
+
        }
 +
    }
 +
 
 +
    template<ranges::forward_range R1, ranges::forward_range R2,
 +
            class Pred = ranges::equal_to,
 +
            class Proj1 = std::identity,
 +
            class Proj2 = std::identity>
 +
    requires std::indirectly_comparable<ranges::iterator_t<R1>,
 +
                                        ranges::iterator_t<R2>,
 +
                                        Pred, Proj1, Proj2>
 +
    constexpr ranges::borrowed_subrange_t<R1>
 +
        operator()(R1&& r1, R2&& r2, Pred pred = {},
 +
                  Proj1 proj1 = {}, Proj2 proj2 = {}) const
 
     {
 
     {
 
         return (*this)(ranges::begin(r1), ranges::end(r1),
 
         return (*this)(ranges::begin(r1), ranges::end(r1),
Line 103: Line 110:
 
};
 
};
  
inline constexpr find_end_fn find_end{};
+
inline constexpr find_end_fn find_end {};
 
}}
 
}}
  
 
===Example===
 
===Example===
{{example|code=
+
{{example
 +
|code=
 
#include <algorithm>
 
#include <algorithm>
 
#include <array>
 
#include <array>
 
#include <cctype>
 
#include <cctype>
 
#include <iostream>
 
#include <iostream>
#include <string_view>
 
 
#include <ranges>
 
#include <ranges>
 +
#include <string_view>
  
void print(std::ranges::forward_range auto const r, int pos) {
+
void print(const auto haystack, const auto needle)
     std::cout << "Found \"";
+
{
     for (const auto c : r) { std::cout << c; }
+
    const auto pos = std::distance(haystack.begin(), needle.begin());
     std::cout << "\" at position " << pos << '\n';
+
    std::cout << "In \"";
 +
    for (const auto c : haystack)
 +
        std::cout << c;
 +
     std::cout << "\" found \"";
 +
     for (const auto c : needle)
 +
        std::cout << c;
 +
     std::cout << "\" at position [" << pos << ".." << pos + needle.size() << ")\n"
 +
        << std::string(4 + pos, ' ') << std::string(needle.size(), '^') << '\n';
 
}
 
}
  
Line 124: Line 139:
 
{
 
{
 
     using namespace std::literals;
 
     using namespace std::literals;
     constexpr auto secret{"password_password_word"sv};
+
     constexpr auto secret{"password password word..."sv};
     constexpr auto hacker{"password"sv};
+
     constexpr auto wanted{"password"sv};
     constexpr std::array digits{1, 2, 3, 0, 1, 2, 3, 1, 2};
+
 
     constexpr std::array sub{-1, -2, -3};
+
     constexpr auto found1 = std::ranges::find_end(
 +
        secret.cbegin(), secret.cend(), wanted.cbegin(), wanted.cend());
 +
     print(secret, found1);
  
     constexpr auto out1 = std::ranges::find_end(
+
     constexpr auto found2 = std::ranges::find_end(secret, "word"sv);
        secret.cbegin(), secret.cend(), hacker.cbegin(), hacker.cend());
+
     print(secret, found2);
     print(out1, std::distance(secret.begin(), out1.begin()));
+
  
     constexpr auto out2 = std::ranges::find_end(secret, "word"sv);
+
     const auto found3 = std::ranges::find_end(secret, "ORD"sv,
    print(out2, std::distance(secret.begin(), out2.begin()));
+
        [](const char x, const char y) { // uses a binary predicate
 +
            return std::tolower(x) == std::tolower(y);
 +
        });
 +
    print(secret, found3);
  
     const auto out3 = std::ranges::find_end(digits, sub,
+
     const auto found4 = std::ranges::find_end(secret, "SWORD"sv, {}, {},
         [](int x, int y) { return x == -y; }); //<- uses a predicate
+
         [](char c) { return std::tolower(c); }); // projects the 2nd range
     print(out3, std::distance(digits.begin(), out3.begin()));
+
     print(secret, found4);
  
     const auto out4 = std::ranges::find_end(secret, "SWORD"sv, {}, {},
+
     static_assert(std::ranges::find_end(secret, "PASS"sv).empty()); // => not found
        [](char c) { return std::tolower(c); }); //<- projects 2nd range
+
    print(out4, std::distance(secret.begin(), out4.begin()));
+
 
}
 
}
| output=
+
|output=
Found "password" at position 9
+
In "password password word..." found "password" at position [9..17)
Found "word" at position 18
+
            ^^^^^^^^
Found "123" at position 4
+
In "password password word..." found "word" at position [18..22)
Found "sword" at position 12
+
                      ^^^^
 +
In "password password word..." found "ord" at position [19..22)
 +
                      ^^^
 +
In "password password word..." found "sword" at position [12..17)
 +
                ^^^^^
 
}}
 
}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/algorithm/dsc find_end}}
+
{{dsc inc|cpp/algorithm/ranges/dsc find_last}}
{{dsc inc | cpp/algorithm/ranges/dsc adjacent_find}}
+
{{dsc inc|cpp/algorithm/ranges/dsc find}}
{{dsc inc | cpp/algorithm/ranges/dsc find}}
+
{{dsc inc|cpp/algorithm/ranges/dsc find_first_of}}
{{dsc inc | cpp/algorithm/ranges/dsc find_first_of}}
+
{{dsc inc|cpp/algorithm/ranges/dsc adjacent_find}}
{{dsc inc | cpp/algorithm/ranges/dsc search}}
+
{{dsc inc|cpp/algorithm/ranges/dsc search}}
{{dsc inc | cpp/algorithm/ranges/dsc search_n}}
+
{{dsc inc|cpp/algorithm/ranges/dsc search_n}}
 +
{{dsc inc|cpp/algorithm/dsc find_end}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 06:21, 22 September 2023

 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
(C++11)                (C++11)(C++11)

Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17)(C++11)
(C++20)(C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
(C++11)
(C++17)
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
 
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
       
       
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
       
       
Permutation operations
Fold operations
Numeric operations
(C++23)            
Operations on uninitialized storage
Return types
 
Defined in header <algorithm>
Call signature
template< std::forward_iterator I1, std::sentinel_for<I1> S1,

          std::forward_iterator I2, std::sentinel_for<I2> S2,
          class Pred = ranges::equal_to,
          class Proj1 = std::identity,
          class Proj2 = std::identity >
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr ranges::subrange<I1>
    find_end( I1 first1, S1 last1, I2 first2, S2 last2,

              Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
(1) (since C++20)
template< ranges::forward_range R1, ranges::forward_range R2,

          class Pred = ranges::equal_to,
          class Proj1 = std::identity,
          class Proj2 = std::identity >
requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                    ranges::iterator_t<R2>,
                                    Pred, Proj1, Proj2>
constexpr ranges::borrowed_subrange_t<R1>
    find_end( R1&& r1, R2&& r2, Pred pred = {},

              Proj1 proj1 = {}, Proj2 proj2 = {} );
(2) (since C++20)
1) Searches for the last occurrence of the sequence [first2last2) in the range [first1last1), after projection with proj1 and proj2 respectively. The projected elements are compared using the binary predicate pred.
2) Same as (1), but uses r1 as the first source range and r2 as the second source range, as if using ranges::begin(r1) as first1, ranges::end(r1) as last1, ranges::begin(r2) as first2, and ranges::end(r2) as last2.

The function-like entities described on this page are niebloids, that is:

In practice, they may be implemented as function objects, or with special compiler extensions.

Contents

[edit] Parameters

first1, last1 - the range of elements to examine (aka haystack)
first2, last2 - the range of elements to search for (aka needle)
r1 - the range of elements to examine (aka haystack)
r2 - the range of elements to search for (aka needle)
pred - binary predicate to compare the elements
proj1 - projection to apply to the elements in the first range
proj2 - projection to apply to the elements in the second range

[edit] Return value

1) ranges::subrange<I1>{} value initialized with expression {i, i + (i == last1 ? 0 : ranges::distance(first2, last2))} that denotes the last occurrence of the sequence [first2last2) in range [first1last1) (after projections with proj1 and proj2). If [first2last2) is empty or if no such sequence is found, the return value is effectively initialized with {last1, last1}.
2) Same as (1), except that the return type is ranges::borrowed_subrange_t<R1>.

[edit] Complexity

At most S·(N-S+1) applications of the corresponding predicate and each projection, where S is ranges::distance(first2, last2) and N is ranges::distance(first1, last1) for (1), or S is ranges::distance(r2) and N is ranges::distance(r1) for (2).

[edit] Notes

An implementation can improve efficiency of the search if the input iterators model std::bidirectional_iterator by searching from the end towards the begin. Modelling the std::random_access_iterator may improve the comparison speed. All this however does not change the theoretical complexity of the worst case.

[edit] Possible implementation

struct find_end_fn
{
    template<std::forward_iterator I1, std::sentinel_for<I1> S1,
             std::forward_iterator I2, std::sentinel_for<I2> S2,
             class Pred = ranges::equal_to,
             class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
    constexpr ranges::subrange<I1>
        operator()(I1 first1, S1 last1,
                   I2 first2, S2 last2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {}) const
    {
        if (first2 == last2)
        {
            auto last_it = ranges::next(first1, last1);
            return {last_it, last_it};
        }
        auto result = ranges::search(
            std::move(first1), last1, first2, last2, pred, proj1, proj2);
 
        if (result.empty())
            return result;
 
        for (;;)
        {
            auto new_result = ranges::search(
                std::next(result.begin()), last1, first2, last2, pred, proj1, proj2);
            if (new_result.empty())
                return result;
            else
                result = std::move(new_result);
        }
    }
 
    template<ranges::forward_range R1, ranges::forward_range R2,
             class Pred = ranges::equal_to,
             class Proj1 = std::identity,
             class Proj2 = std::identity>
    requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                        ranges::iterator_t<R2>,
                                        Pred, Proj1, Proj2>
    constexpr ranges::borrowed_subrange_t<R1>
        operator()(R1&& r1, R2&& r2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {}) const
    {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(pred),
                       std::move(proj1), std::move(proj2));
    }
};
 
inline constexpr find_end_fn find_end {};

[edit] Example

#include <algorithm>
#include <array>
#include <cctype>
#include <iostream>
#include <ranges>
#include <string_view>
 
void print(const auto haystack, const auto needle)
{
    const auto pos = std::distance(haystack.begin(), needle.begin());
    std::cout << "In \"";
    for (const auto c : haystack)
        std::cout << c;
    std::cout << "\" found \"";
    for (const auto c : needle)
        std::cout << c;
    std::cout << "\" at position [" << pos << ".." << pos + needle.size() << ")\n"
        << std::string(4 + pos, ' ') << std::string(needle.size(), '^') << '\n';
}
 
int main()
{
    using namespace std::literals;
    constexpr auto secret{"password password word..."sv};
    constexpr auto wanted{"password"sv};
 
    constexpr auto found1 = std::ranges::find_end(
        secret.cbegin(), secret.cend(), wanted.cbegin(), wanted.cend());
    print(secret, found1);
 
    constexpr auto found2 = std::ranges::find_end(secret, "word"sv);
    print(secret, found2);
 
    const auto found3 = std::ranges::find_end(secret, "ORD"sv,
        [](const char x, const char y) { // uses a binary predicate
            return std::tolower(x) == std::tolower(y);
        });
    print(secret, found3);
 
    const auto found4 = std::ranges::find_end(secret, "SWORD"sv, {}, {},
        [](char c) { return std::tolower(c); }); // projects the 2nd range
    print(secret, found4);
 
    static_assert(std::ranges::find_end(secret, "PASS"sv).empty()); // => not found
}

Output:

In "password password word..." found "password" at position [9..17)
             ^^^^^^^^
In "password password word..." found "word" at position [18..22)
                      ^^^^
In "password password word..." found "ord" at position [19..22)
                       ^^^
In "password password word..." found "sword" at position [12..17)
                ^^^^^

[edit] See also

finds the last element satisfying specific criteria
(niebloid)[edit]
finds the first element satisfying specific criteria
(niebloid)[edit]
searches for any one of a set of elements
(niebloid)[edit]
finds the first two adjacent items that are equal (or satisfy a given predicate)
(niebloid)[edit]
searches for the first occurrence of a range of elements
(niebloid)[edit]
searches for the first occurrence of a number consecutive copies of an element in a range
(niebloid)[edit]
finds the last sequence of elements in a certain range
(function template) [edit]