字符串的第n个出现位置索引

16

如何在一行中找到给定字符串第n次出现的索引?我需要从该索引处获取子字符串。是否可以通过C++中的任何函数实现?

7个回答

17

Boost库中有一个find_nth模板函数:http://www.boost.org/doc/libs/1_54_0/doc/html/boost/algorithm/find_nth.html

#include <iostream>
#include <boost/algorithm/string/find.hpp>

using namespace std;
using namespace boost;

int main() {

    string a = "The rain in Spain falls mainly on the plain";

    iterator_range<string::iterator> r = find_nth(a, "ain", 2);
    cout << std::distance(a.begin(), r.begin()) << endl;

    return 0;
}

这个答案会给出最后一次出现的位置,即25。请问我如何检索真正的第二个索引。 - huahsin68
2
@huahsin68:正如在find_nth文档中所述,索引是从零开始的。只需使用1即可找到第二个出现。 - Vladimir Sinenko

12

你可以使用std::string::find来查找字符串,并跟踪返回的位置。在执行此操作时,您还可以检查所需字符串是否未找到,并返回-1。

#include <string>

int nthOccurrence(const std::string& str, const std::string& findMe, int nth)
{
    size_t  pos = 0;
    int     cnt = 0;

    while( cnt != nth )
    {
        pos+=1;
        pos = str.find(findMe, pos);
        if ( pos == std::string::npos )
            return -1;
        cnt++;
    }
    return pos;
}

只需要进行一个小修正,将pos初始化为-1,因为findme使用的是从零开始的索引。 - rkscodes

8
您可以使用以下函数。
#include <string.h>

int strpos(char *haystack, char *needle, int nth)
{
    char *res = haystack;
    for(int i = 1; i <= nth; i++)
    {
        res = strstr(res, needle);
        if (!res)
            return -1;
        else if(i != nth)
            res++;
    }
    return res - haystack;
}

如果找不到第n个匹配项,则返回-1。

3
"res = res++;" 这一行似乎没有任何作用,建议将其改为 "res++;"。 - Streamsoup
甚至更好的是,++res - Kyle

4
使用std::string::find可以简单地实现此操作。
size_t find_nth(const string& haystack, size_t pos, const string& needle, size_t nth) 
{
    size_t found_pos = haystack.find(needle, pos);
    if(0 == nth || string::npos == found_pos)  return found_pos;
    return find_nth(haystack, found_pos+1, needle, nth-1);
}

这段代码在无法很好地找到特定出现的情况下处理得不够好。在我的情况下,它返回了一个不合理大的数字。我喜欢这段代码的简洁性和对 size_t 的使用。 - Simple Sandman
2
我认为大数是 string::npos。如果没有找到匹配项,该函数应该像 string::find 一样返回 string::npos - rmorarka
1
这很有道理。那么我只需要自己处理 string::npos 即可。感谢您提供的代码片段! - Simple Sandman
我们正在尝试找到第n个出现的位置。我相信这个解决方案似乎返回了第n+1个出现或string::npos... - wideize

1
这个模板函数应该能完成工作。
template<typename Iter>
Iter nth_occurence(Iter first, Iter last,
                   Iter first_, Iter last_,
                   unsigned nth)
{
  Iter it = std::search(first, last, first_, last_);
  if (nth == 0) return it;
  if (it == last) return it;
  return nth_occurence(it + std::distance(first_, last_), last,
                       first_, last_, nth -1);
}

使用方法

int main()
{
  std::string a = "hello world world world end";
  std::string b = "world";
  auto it1 = nth_occurence(begin(a), end(a), begin(b), end(b), 0);
  auto it2 = nth_occurence(begin(a), end(a), begin(b), end(b), 1);
  auto it3 = nth_occurence(begin(a), end(a), begin(b), end(b), 2);
  auto it4 = nth_occurence(begin(a), end(a), begin(b), end(b), 3);

  std::cout << std::distance(begin(a), it1) << "\n";
  std::cout << std::distance(begin(a), it2) << "\n";
  std::cout << std::distance(begin(a), it3) << "\n";
  std::cout << std::boolalpha << (it4 == end(a)) << "\n";
}

=> 6, 12, 18, true

请问您正在使用哪个版本的boost? - huahsin68
@huahsin68 这里的 Boost 在哪里? - Lightness Races in Orbit

1
另一种方法是利用std::stringfind_first_of/find_last_of的最后一个参数。对于last-nth搜索,可以按以下方式进行:
auto find_last_nth(const std::string& haystack, const std::string& needle, size_t n = 1)
{
    assert(0 != n);

    auto found_last = haystack.length();
    while (true)
    {
        found_last = haystack.find_last_of(needle, found_last - 1);

        if (0 == --n || std::string::npos == found_last)
        {
            return found_last;
        }
    }
}

0

我非常喜欢rcs的答案,他巧妙地利用了指针。我认为,在不使用boost库的情况下,这是实现OP想要的结果最干净的方法。然而,我在某些没有使用指针的代码中实现它时遇到了麻烦(我自己还是个初学者),因此这里提供一个等效的答案,既不使用指针也不使用boost库。

int strpos(string haystack, char needle, int nth)
{// Will return position of n-th occurence of a char in a string.
        string read;    // A string that will contain the read part of the haystack
        for (int i=1 ; i<nth+1 ; ++i)
        {
                std::size_t found = haystack.find(needle);
                read += haystack.substr(0,found+1); // the read part of the haystack is stocked in the read string
                haystack.erase(0, found+1);     // remove the read part of the haystack up to the i-th needle
                if (i == nth)
                {
                        return read.size();
                }
        }
        return -1;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接