【问题标题】:Finding a string of numbers within another string在另一个字符串中查找一串数字
【发布时间】:2014-01-25 15:56:01
【问题描述】:

所以,我在 C++ 中遇到了问题。

我需要搜索一个由五个数字组成的字符串,这些数字并不总是在字符串中的同一位置。

例如,有时源字符串可能是“sjdjfut93835sxx”,有时可能是“jj3333333335”。

在第一个字符串中,我需要提取“93835”。在第二个字符串中,我不会提取任何内容,因为数字字符串超过了五个字符。

我需要找到长度为 5 个字符且只有数字、中间没有字母的数字字符串。

最简单的方法是什么?我在这方面遇到了很多麻烦,在 Google 上的任何地方或过去的 StackOverflow 问题上都找不到答案

谢谢!

【问题讨论】:

  • 一个简单的嵌套循环和std::isdigit 函数就足够了。
  • 到目前为止你尝试了什么?
  • 或者使用std::find_if(以std::isdigit为谓词)获取数字序列的开头,然后使用std::find_if_not查找结尾。使用std::distance 检查这些位置之间的“距离”(即长度)。
  • 如果要搜索的大字符串中有多个这样的字符串,你会返回什么?

标签: c++ string substring


【解决方案1】:

尝试将任务分成两个步骤。

首先,使用正则表达式之类的方法提取所有数字字符串(在您的示例中为 93835 和 3333333335)。

其次,删除所有长度不是 5 个字符的结果。

【讨论】:

  • 嗯,正则表达式完全可以同时完成这两个步骤:(^|[^0-9])([0-9]{5,5})($|[^0-9])。当然,不确定在 c++ 中找到一个库有多么容易。
  • @ZacHowland 搞砸了那个小小的 C++11……我的意思是,我知道现在是 2014 年,但由于某种原因,事情进展缓慢。
  • @ebyrob 我已经有一段时间没有复习我的正则表达式语法了,但这会返回找到的任何 5 个数字字符的序列吗? IE。第二个示例将返回 33333(可能更多)。
  • @JoshuaMagashazi 它应该。 [0-9]{5,5} 将匹配 0-9 连续的任意 5 个数字。但是,然后我想排除任何“额外”的内容,并且还能够使用正则表达式组 \2 我想,返回我们真正感兴趣的匹配(当匹配发生时)。
  • @ebyrob 此外,表达式可以简单地为\d{5}。如果 OP 想要返回字符串中 5 个连续数字的所有可能组合,他可以返回一组字符串,每个字符串包含 5 个数字。
【解决方案2】:
string text="sjdjfut93835sxx";

int digitCount=0;
string aux="";
for(int i=0; i<strlen(text); i++)
{

if(text[i]>=48 && text[i]<=57) // if is a digit
{
digitCount++;
aux+=text[i];
if(digitCount==5)
{
cout<<"I found it! "<<aux;
}

}
else
{
aux="";
digitCount=0;
}
}

【讨论】:

  • strlen 在字符串上,在 for 循环条件中?不使用迭代器?与4857 而不是'0''9' 相比?
  • 我不能和48和57比较,因为text[i]是char,我要和ascii码比较。
  • 是的,你应该这样做。但你正在做:if(text[i]&gt;=48 &amp;&amp; text[i]&lt;=57) // if is a digit
  • 是的,因为如果字符在区间 [48;57] 中,则表示这是一个数字。
  • 我理解你的所作所为,但你最好做类似(text[i] &gt;= '0' &amp;&amp; text[i] &lt;= '9')...或者更好的std::isdigit(text[i])
【解决方案3】:

使用 DFA(确定性有限自动机)算法和模式匹配算法非常简单。例如Boyer-Moore 算法或Knuth-Morris-Pratt 的算法。您可以在任何算法书籍中找到对它们的详尽描述。

否则,正如 Joshua 所说,您可能会使用一些现成的正则表达式库并由它完成搜索和模式匹配工作。

您的具体问题也可以通过手工制作的解决方案(如果我理解正确的话)“手动”解决,如下所示:

  • 一次扫描一个字符的字符串
  • 如果遇到一个数字,就开始数下一个有多少
  • 如果 > 5,则放下它并重置计数器,直到找到另一个数字

非常简单,O(N)

【讨论】:

    【解决方案4】:

    您可以使用以下状态创建简单的有限状态机:

    1) 等待数字 2)有第一个数字,等待第二个数字 3)有第二个数字,等待第三个数字 4) ... 5) ... 6) ... 7) 有第五位数字,等待字母或字符串结尾 8) 完成。返回字符串。

    【讨论】:

      【解决方案5】:

      std::regex

      int extract(const string& str) {
        smatch result;
        regex r("\\d{5}");
        regex_search(str, result, r);
        return stoi(result.str());
      }
      

      如果找不到号码,这个函数(stoi)会抛出异常。

      Edit:: 此函数还匹配包含超过 5 个连续数字的字符串。
      您可以将正则表达式修改为(^|\\D)\\d{5}($|\\D),然后在调用stoi 之前删除第一个非数字(如果有)。

      【讨论】:

      • 或者修改返回值,改为返回std::string。如果返回值为空,则没有找到。否则,您可以使用 std::stol 轻松转换它。
      • @ZacHowland 是的,我通常为此使用boost::optional&lt;int&gt;
      • 这不是完全匹配...其他数字旁边的 5 个数字吗?
      • @yngum 也可以。我希望他们没有从提议的 C++14 标准中删除 optional&lt;&gt; 模板...
      • (?&lt;!\d)\d{5}(?!\d) 会工作。我不确定 C++ 正则表达式引擎是否支持负向前/向后。
      猜你喜欢
      • 2022-06-17
      • 2021-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-19
      • 1970-01-01
      • 2018-10-03
      • 1970-01-01
      相关资源
      最近更新 更多