【问题标题】:Regex to build a vector from braces正则表达式从大括号构建向量
【发布时间】:2013-11-27 15:52:01
【问题描述】:

我想转一个std::string 如:

"{1, 2}, {one, two}, {123, onetwothree}"

进入std::vectorstd::pairsstd::strings 看起来像:

std::vector<std::pair<std::string, std::string>> v = {{"1", "2"}, {"one", "two"}, {"123", "onetwothree"}};
// where, for instance
v[0] == std::make_pair("1", "2"); // etc.

这似乎是使用std::regex 最容易解析原始std::string 的情况,但我不是正则表达式专家(或新手),更不用说std::regex 专家了。对这里的食谱有什么想法吗?

【问题讨论】:

  • 到目前为止你已经尝试过什么?
  • "{1, {2, 3} { {a, b} } }" 呢?
  • 现在,我正在使用 std::string 自己的 find 方法手动执行此操作。不是正则表达式的人,这似乎是一个很好的入门案例,但我发现的示例倾向于返回单个大括号匹配的内容,而不是遍历大括号匹配的多个匹配。
  • 格式方面,“{first, second}, {third, Fourth}等”比较严格。这是一个字符串对列表,如果这样更清楚的话。
  • 我在stackoverflow.com/questions/13227802/… 找到的例子是正确的,但是太微不足道了。我只是不知道如何将其扩展到这个更复杂的案例。如果最好的话,我可以使用一些混合字符串/正则表达式解决方案。

标签: c++ regex parsing c++11


【解决方案1】:

目前,&lt;regex&gt; 不适用于GCC,这里有一个 boost 版本,用-lboost_regex 编译。

boost capture 适合这种情况,但默认情况下未启用。

这是原帖:Boost C++ regex - how to get multiple matches

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

using namespace std;

int main()
{
  string str = "{1, 2}, {one, two}, {123, onetwothree}";

  boost::regex pair_pat("\\{[^{}]+\\}");
  boost::regex elem_pat("\\s*[^,{}]+\\s*");

  boost::sregex_token_iterator end;

  for(boost::sregex_token_iterator iter(str.begin(), str.end(), pair_pat, 0);
      iter != end; ++iter) {

    string pair_str = *iter;
    cout << pair_str << endl;

    for (boost::sregex_token_iterator it(pair_str.begin(), pair_str.end(), elem_pat, 0);
         it != end; ++it)
      cout << *it << endl;
  }

  return 0;
}

【讨论】:

    【解决方案2】:

    匹配模式非常简单:“\{\s*(\w+)\s*\,\s*(\w+)\s*\}”所以我们只需要循环并组装所有匹配项. C++11 使这非常简单。试一试:

    std::string str = "{1, 2}, {one, two}, {123, onetwothree}";
    std::vector<std::pair<std::string, std::string>> pairs;
    std::regex exp(R"(\{\s*(\w+)\s*\,\s*(\w+)\s*\})");
    std::smatch sm;
    std::string::const_iterator cit = str.cbegin();
    while (std::regex_search(cit, str.cend(), sm, exp)) {
        if (sm.size() == 3) // 3 = match, first item, second item
            pairs.emplace_back(sm[1].str(), sm[2].str());
        // the next line is a bit cryptic, but it just puts cit at the remaining string start
        cit = sm[0].second;
    }
    

    编辑:解释它是如何工作的:它一次匹配一个模式,每次匹配后使用一个常量迭代器指向余数:

    {1, 2}, {one, two}, {123, onetwothree}
    ^ iterator cit
    -- regex_search matches "{1, 2}" sm[1] == "1", sm[2] == "2"
    
    {1, 2}, {one, two}, {123, onetwothree}
          ^ iterator cit
    -- regex_search matches "{one, two}" sm[1] == "one", sm[2] == "two"
    
    {1, 2}, {one, two}, {123, onetwothree}
                      ^ iterator cit
    -- regex_search matches "{123, onetwothree}" sm[1] == "123", sm[2] == "onetwothree"
    
    {1, 2}, {one, two}, {123, onetwothree}
                                          ^ iterator cit
    -- regex_search returns false, no match
    

    【讨论】:

    • 我把它放进去,它的工作方式和我想要的完全一样。我想我在这里最大的问题是了解正则表达式如何知道查找 N 个匹配项。我正在根据搜索和其他人的 cmets 来玩其他想法,但我很难获得超过外部匹配的 {} 集。
    • 啊!所以正则表达式一次只匹配一个,但它是字符串迭代器,它沿着字符串前进,寻找随后的任何匹配。感谢那里的额外解释。 (我应该看看迭代器是如何被更密切地使用的!)
    • 我添加了一个关于它是如何工作的解释——正则表达式不匹配 N 个匹配,而是第一个匹配。然后我们使用迭代器来迭代剩余部分。在循环中执行此操作可以让我们每场比赛。
    • 听起来很像 std::regex_token_iterator 所做的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多