【问题标题】:std::regex: Match string consisting of digits and white space and extract digits. How?std::regex:匹配由数字和空格组成的字符串并提取数字。如何?
【发布时间】:2020-06-14 09:45:47
【问题描述】:

我想同时做两件事:将字符串与模式匹配并提取组。

字符串由空格和数字组成。我想将字符串与此模式匹配。此外,我想使用 std::smatch 提取数字(不是数字,仅单个数字)。

我尝试了很多,但没有成功。

对于骗子猎人:我检查了很多关于 SO 的答案,但我找不到解决方案。

然后我尝试使用std::sregex_token_iterator。结果也让我感到困惑。在

#include <string>
#include <regex>
#include <vector>
#include <iterator>

const std::regex re1{ R"(((?:\s*)|(\d))+)" };

const std::regex re2{ R"(\s*(\d)\s*)" };

int main() {
    std::string test("   123 45 6   ");
    std::smatch sm;

    bool valid1 = std::regex_match(test, sm, re1);
    std::vector<std::string> v(std::sregex_token_iterator(test.begin(), test.end(), re2), {});
    return 0;
}

向量不仅包含数字,还包含空格。我想只有数字。

smatch 不包含任何数字。

我知道,我可以先从字符串中删除所有空格,但应该有更好的一步解决方案。


什么是正确的正则表达式 1. 将字符串与我描述的模式匹配 2. 将所有单个数字提取到 smatch 中?

【问题讨论】:

  • 试试\s*\d,它会匹配0+个空格,然后是个位数
  • @MichałTurczyn:抱歉,这行不通。

标签: c++ regex


【解决方案1】:

你需要验证的模式是

\s*(?:\d\s*)*

查看regex demo(注意我添加了^$以使模式匹配正则表达式测试站点的整个字符串,因为您在代码中使用等效的regex_match,它需要完整的字符串匹配)。

接下来,一旦你的字符串通过第一个正则表达式验证,你只需要提取任何一个数字:

const std::regex re2{ R"(\d)" };
// ...
std::vector<std::string> v(std::sregex_token_iterator(test.begin(), test.end(), re2), {});

完整的working snippet:

#include <string>
#include <regex>
#include <vector>
#include <iterator>
#include <iostream>

const std::regex re1{ R"(\s*(?:\d\s*)*)" };

const std::regex re2{ R"(\d)" };

int main() {
    std::string test("   123 45 6   ");
    std::smatch sm;

    bool valid1 = std::regex_match(test, sm, re1);
    std::vector<std::string> v(std::sregex_token_iterator(test.begin(), test.end(), re2), {});
    for (auto i: v)
        std::cout << i << std::endl;

    return 0;
}

输出:

1
2
3
4
5
6

使用 Boost 的替代解决方案

只有当整个字符串由空格和数字组成时,您才可以使用正则表达式来分别匹配所有数字

\G\s*(\d)(?=[\s\d]*$)

请参阅regex demo

详情

  • \G - 字符串的开头或前面成功匹配的结尾
  • \s* - 0+ 个空格
  • (\d) - 在第 1 组中捕获的数字(当传递 1 作为 boost::sregex_token_iterator iter(test.begin(), test.end(), re2, 1) 中的最后一个参数时,我们将只返回此值)
  • (?=[\s\d]*$) - 必须有 0 个或多个空格或数字,然后是字符串的结尾紧挨当前位置的右侧。

查看whole C++ snippet(使用-lboost_regex 选项编译):

#include <iostream>
#include <vector>
#include <boost/regex.hpp>

int main()
{
    std::string test("   123 45 6   ");
    boost::regex re2(R"(\G\s*(\d)(?=[\s\d]*$))");
    boost::sregex_token_iterator iter(test.begin(), test.end(), re2, 1);
    boost::sregex_token_iterator end;
    std::vector<std::string> v(iter, end);
    for (auto i: v)
        std::cout << i << std::endl;

    return 0;
}

【讨论】:

  • 非常感谢。 (\d) 对我来说很清楚。我想知道为什么我得到了空格,尽管只有(\d) 在组中(在括号中)。好吧,无论如何。对我来说更重要的是std::sregex_match。比赛的天真方法是(\s|\d)*。但这不会将任何数字放入组中,并且不会在匹配结果中放入我想要的。这就是我担心的一点。如何同时匹配和得到结果(通过smatch)?
  • @ArminMontigny 你一定在问repeated capturing group。不,std::regex 不可能。使用Boost,你could get something working,但你需要以特定的方式编译它,有人说它比解决方案更令人头疼。见another 2-step workaround
  • @ArminMontigny 查看使用 Boost 的替代解决方案。
  • 再次感谢您的帮助。明白了。 . . .但是想知道为什么标准 C++ 不能处理这么简单的任务。无论如何 +1 +接受。
  • @ArminMontigny 因为它所支持的正则表达式都不支持\G 或无限宽度的lookbehind。也不为每个组捕获堆栈。
猜你喜欢
  • 2020-07-03
  • 2019-03-14
  • 1970-01-01
  • 2020-11-13
  • 2018-08-25
  • 2021-09-10
  • 2020-06-10
  • 2021-09-30
  • 1970-01-01
相关资源
最近更新 更多