使用 strtok 查找子字符串

Using strtok to find substring

我有一串很多字母

string path = "cxzaserds";

和一个目标词

string word = "cars";

在我的函数 match() 中,如果在路径中找到(按顺序)来自 word 的字符,我想 return 为真,在这种情况下它将 return true('c' 在 'a' 之前在 'r' 在 path 字符串中的 's' 之前出现)。

我正在尝试使用 strtok() 逐个查找每个字符,分隔符是当前索引的字母。

我的进步:

bool match (string path, string word)
{
  char * cstr = new char [path.length()+1]; //workaround for strtok on string
  std::strcpy (cstr, path.c_str());

    char *p;

  for (int i = 0 ; i < path.length(); i++)
    {
    //error here, "invalid conversion from 'char' to 'const char*'
      p = strtok (cstr, word[i]);

      if (p != NULL) //if strtok found word[i]
        continue;
      else return false; //was NULL, word not found
    }

  return true; //made it through, return true
}

在 C++ 页面上,分隔符下显示:

这些可以与另一个调用不同。

http://www.cplusplus.com/reference/cstring/strtok/

如何将分隔符更改为 strtok returns 非空? 或其他(更简单的)解决方案?

我已经回答了这个问题,所以我不想在这里完全重复。这个问题是在这里问的,但我找不到。 但是您可以在 my personal forum

看到答案

虽然答案是用俄语写的,但代码是用英语写的。:) 此外,您可以使用网络服务翻译来翻译描述。

至于将标准 C 函数 strtokstd::string 类型的对象一起使用,那只是一个坏主意,不应使用。

另一种方法是使用标准算法 std::all_of 以及标准 C 函数 strchr

您写了:

p = strtok(cstr, word[i]);

作为第二个参数,您要传递第 i 个字符(类型为 char)。

但是,如文档所述,第二个参数必须是 const char * 类型,这意味着它是一个分隔符数组。所以你的类型不匹配。

最简单的解决方案是创建一个分隔符数组(注意它是 NUL 终止的,它实际上是一个只有一个字母的 C 风格字符串):

char delimiters[] = { word[i], '[=11=]' };

然后像这样使用它:

p = strtok(cstr, delimiters);

另一方面,这种方法是非 C++ 风格的,在现实生活中您可能想要别的东西。

strchr 在这个问题上比 strtok 好多了;实际上,正如其他人提到的那样,strtok 的设计确实很糟糕,很难想象在哪些情况下使用它是个好主意。

strchr 查找 C 字符串中某个字符的第一次出现。

即使在 C:

中,这个使用 strchr 的问题也变成了一行
int match(const char *needle, const char *haystack) {
    while (haystack && *needle) {
        haystack = strchr(haystack, *needle++);
    }
    return haystack != NULL;
}

正如 Vlad 提到的,您不应该混合使用 STL 代码 (std::string) 和经典 C 代码 (strtok())。

您可以使用 std::string 成员,例如 find()find_first_of() 来解决您的问题:

bool match(const std::string &path, const std::string &word) {
    std::size_t pos = 0; // position of the last match

    // iterate over all characters in 'word'
    for (std::size_t i = 0; i < word.length(); ++i) {
        // look for the next character and store the new position
        if ((pos = path.find(word[i], pos)) == std::string::npos)
            return false; // return false if it couldn't be found
    }
    return true; // all characters have been found in order
}

考虑到您的问题以及 C/C++ 允许您使用普通下标处理单个字符的事实,那么 strtok 似乎只会使解决方案复杂化。

类似于(未经测试的代码!):

boolean hasWord ( char * needle, char * haystack) {
   int nlen = strlen(needle);
   int npos = 0;
   int hlen = strlen(haystack);
   int hpos = 0;
   for (hpos = 0 ; hpos < hlen ; hpos++) {
        if (needle[npos] == haystack[hpos]) {
            // got a match now look for next letter
            npos++;
            if (npos >= nlen) {
                // all letters now matched in sequence
                return true;
            }
        }
   }
   return false;
}