提升正则表达式以捕获所有重复的模式

时间:2017-04-01 19:34:47

标签: c++ regex boost

我有一个简单的文本文件,其中包含以下内容:

VALUE "foo"
ANOTHERVALUE "bar"
YETANOTHERVALUE "barbar"

第1列中的值是已知的。

我想捕获第1列和第2列中的所有内容。

我的解决方案涉及手动将第1列(已知)的所有可能值写入正则表达式字符串,但显然这不是理想的做法,因为我基本上重复代码,这不允许排序灵活:< / p>

const char* re =
     "^[[:space:]]*"
     "(VALUE)[[:space:]]*\"(.*)\"[[:space:]]*"
     "(ANOTHERVALUE)[[:space:]]*\"(.*)\"[[:space:]]*"
     "(YETANOTHERVALUE)[[:space:]]*\"(.*)\"[[:space:]]*";

2 个答案:

答案 0 :(得分:1)

我在这里引用了评论者Igor Tandetnik,因为他几乎在评论中给出了完整的答案:

  

正则表达式捕获与所有子串一样多的子串   左括号表达式[...]

     

解决此问题的正确方法是编写与a匹配的正则表达式   单对,[...]

\s*([a-zA-Z]+)\s*"(.*?)"

注意:

  • \s相当于[[:space:]]
  • .*?用于在第二个"后停止搜索,而不是字符串中的最后一个"
  

并重复应用,例如通过std :: regex_iterator

等效提升为boost::regex_iterator

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

const boost::regex expr{ R"__(\s*([a-zA-Z]+)\s*"(.*?)")__" };

const std::string s =
R"(VALUE "foo" 
ANOTHERVALUE "bar" 
YETANOTHERVALUE "barbar"
)";

int main() {
    boost::sregex_iterator it{ begin(s), end(s), expr }, itEnd;

    std::for_each( it, itEnd, []( const boost::smatch& m ){
        std::cout << m[1] << '\n' << m[2] << std::endl;
    });
}

Live demo.

注意:

答案 1 :(得分:1)

我会在这里使用一个小灵魂解析器:

阅读地图

<强> Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp> // reading maps
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>

#include <iostream>
#include <fstream>
#include <map>

auto read_config_map(std::istream& stream) {
    std::map<std::string, std::string> settings;

    boost::spirit::istream_iterator f(stream >> std::noskipws), l;
    using namespace boost::spirit::x3;

    auto key_ = lexeme [ +upper ];
    auto value_ = lexeme [ '"' >> *~char_('"') >> '"' ];

    if (!phrase_parse(f, l, -(key_ >> value_) % eol >> eoi, blank, settings))
        throw std::invalid_argument("cannot parse config map");

    return settings;
}

auto read_config_map(std::string const& fname) {
    std::ifstream stream(fname);
    return read_config_map(stream);
}

int main() {
    for (auto&& entry : read_config_map(std::cin))
        std::cout << "Key:'" << entry.first << "' Value:'" << entry.second << "'\n";
}

打印:

Key:'ANOTHERVALUE' Value:'bar'
Key:'VALUE' Value:'foo'
Key:'YETANOTHERVALUE' Value:'barbar'