【问题标题】:modify regex to include comma修改正则表达式以包含逗号
【发布时间】:2017-12-12 08:48:30
【问题描述】:

我有以下字符串:

arg1('value1') arg2('value '')2') arg3('user\'~!@#$%^&*_~!@#$%^&"*_-=+[{]}\|;:<.>?21')

提取值的正则表达式如下所示:

boost::regex re_arg_values("('[^']*(?:''[^']*)*'[^)]*)");

上面的正则表达式正确地提取了值。但是当我包含逗号时,代码会失败。例如:

  arg1('value1') arg2('value '')2') arg3('user\'~!@#$%^&*_~!@#$%^&"*_-=+[{]}\|;:<.>?21**,**')

我应该如何修改这个正则表达式以包含逗号? 供参考。该值可以包含空格、特殊字符以及制表符。代码在 CPP 中。

提前致谢。

【问题讨论】:

  • 我不确定,你是在re_arg_values("(\('[^']*(?:''[^']*)*'[^)]*\))")之后吗?
  • @WiktorStribiżew,我更喜欢修改这个: boost::regex re_arg_values("('[^']*(?:''[^']*)*'[^)]*) ");这不能包括逗号或右括号。你能帮帮我吗?
  • 其实这是在接受:arg('user()~!@#$%^&*_-=+[{]}\\|;:2"<.>? ') 但它不适用于“,”(逗号)。有什么方法可以在正则表达式中明确声明接受吗??
  • 请注意反斜杠。当您在常规字符串文字中使用它们时,您必须使用双反斜杠来定义文字反斜杠。现在,如果您不提供 您现在正在测试的确切小提琴/代码 sn-p (您将不断回信说它不起作用),如果您的字符串文字是写的,我无法为您提供太多帮助带有单个反斜杠,并且您没有使用原始字符串文字。
  • 您当前的"('[^']*(?:''[^']*)*'[^)]*)" 模式与外括号不匹配,因为它现在是一个捕获组。您可以删除外括号,仍然会得到相同的结果。

标签: c++ regex boost


【解决方案1】:

我不会在这里使用正则表达式。

目标必须是解析值,毫无疑问,它们会有有用的值,您需要对其进行解释。

我会设计一个像这样的数据结构:

#include <map>

namespace Config {
    using Key = std::string;
    using Value = boost::variant<int, std::string, bool>;
    using Setting = std::pair<Key, Value>;
    using Settings = std::map<Key, Value>;
}

为此,您可以使用 Boost Spirit 编写 1:1 解析器:

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_pair.hpp>

namespace Parser {
    using It = std::string::const_iterator;
    using namespace Config;
    namespace qi = boost::spirit::qi;

    using Skip = qi::blank_type;
    qi::rule<It, std::string()>   quoted_   = "'" >> *(
            "'" >> qi::char_("'") // double ''
          | '\\' >> qi::char_     // any character escaped
          | ~qi::char_("'")       // non-quotes
       ) >> "'";
    qi::rule<It, Key()>           key_      = +qi::char_("a-zA-Z0-9_"); // for example
    qi::rule<It, Value()>         value_    = qi::int_ | quoted_ | qi::bool_;
    qi::rule<It, Setting(), Skip> setting_  = key_ >> '(' >> value_ >> ')';
    qi::rule<It, Settings()>      settings_ = qi::skip(qi::blank) [*setting_];
}

注意这是怎么回事

  • 正确解释非字符串值
  • 指定键的外观并对其进行解析
  • 解释字符串转义,因此映射中的Value 在取消转义后包含“真实”字符串
  • 忽略值外的空白(如果您也想忽略换行符作为空白,请使用space_type

你可以像这样使用它:

int main() {
    std::string const input = R"(    arg1('value1') arg2('value '')2') arg3('user\'~!@#$%^&*_~!@#$%^&"*_-=+[{]}\|;:<.>?21**,**'))";

    Config::Settings map;
    if (parse(input.begin(), input.end(), Parser::settings_, map)) {
        for(auto& entry : map)
            std::cout << "config setting {" << entry.first << ", " << entry.second << "}\n";
    }
}

打印出来的

config setting {arg1, value1}
config setting {arg2, value ')2}
config setting {arg3, user'~!@#$%^&*_~!@#$%^&"*_-=+[{]}|;:<.>?21**,**}

现场演示

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <map>
#include <boost/fusion/adapted/std_pair.hpp>

namespace Config {
    using Key = std::string;
    using Value = boost::variant<int, std::string, bool>;
    using Setting = std::pair<Key, Value>;
    using Settings = std::map<Key, Value>;
}

namespace Parser {
    using It = std::string::const_iterator;
    using namespace Config;
    namespace qi = boost::spirit::qi;

    using Skip = qi::blank_type;
    qi::rule<It, std::string()>   quoted_   = "'" >> *(
            "'" >> qi::char_("'") // double ''
          | '\\' >> qi::char_     // any character escaped
          | ~qi::char_("'")       // non-quotes
       ) >> "'";
    qi::rule<It, Key()>           key_      = +qi::char_("a-zA-Z0-9_"); // for example
    qi::rule<It, Value()>         value_    = qi::int_ | quoted_ | qi::bool_;
    qi::rule<It, Setting(), Skip> setting_  = key_ >> '(' >> value_ >> ')';
    qi::rule<It, Settings()>      settings_ = qi::skip(qi::blank) [*setting_];
}

int main() {
    std::string const input = R"(    arg1('value1') arg2('value '')2') arg3('user\'~!@#$%^&*_~!@#$%^&"*_-=+[{]}\|;:<.>?21**,**'))";

    Config::Settings map;
    if (parse(input.begin(), input.end(), Parser::settings_, map)) {
        for(auto& entry : map)
            std::cout << "config setting {" << entry.first << ", " << entry.second << "}\n";
    }
}

奖金

为了比较,这里是“相同”但使用正则表达式:

Live On Coliru

#include <boost/regex.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <map>

namespace Config {
    using Key = std::string;
    using RawValue = std::string;
    using Settings = std::map<Key, RawValue>;

    Settings parse(std::string const& input) {
        Settings settings;

        boost::regex re(R"((\w+)\(('.*?')\))");
        auto f = boost::make_regex_iterator(input, re);

        for (auto& match : boost::make_iterator_range(f, {}))
            settings.emplace(match[1].str(), match[2].str());

        return settings;
    }
}

int main() {
    std::string const input = R"(    arg1('value1') arg2('value '')2') arg3('user\'~!@#$%^&*_~!@#$%^&"*_-=+[{]}\|;:<.>?21**,**'))";

    Config::Settings map = Config::parse(input);
    for(auto& entry : map)
        std::cout << "config setting {" << entry.first << ", " << entry.second << "}\n";
}

打印

config setting {arg1, 'value1'}
config setting {arg2, 'value ''}
config setting {arg3, 'user\'~!@#$%^&*_~!@#$%^&"*_-=+[{]}\|;:<.>?21**,**'}

注意事项:

  • 它不再解释和转换任何值
  • 它不再处理转义
  • 它需要对 boost_regex 的额外运行时库依赖

【讨论】:

猜你喜欢
  • 2015-09-07
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 2021-10-05
  • 2021-10-31
  • 1970-01-01
  • 2021-07-31
  • 1970-01-01
相关资源
最近更新 更多