问题 从std :: regex中提取原始正则表达式模式


我有一个函数,它试图将给定的字符串与给定的正则表达式模式匹配。如果它不匹配,它应该创建一个指示这种情况的字符串,并包括它失败的正则表达式模式和字符串的内容。类似的东西:

bool validate_content(const std::string & str, const std::regex & pattern, std::vector<std::string> & errors)
{
    if ( false == std::regex_match(str, pattern) )
    {
        std::stringstream error_str;
        // error_str << "Pattern match failure: " << pattern << ", content: " << str;
        errors.push_back(error_str.str());
        return false;
    }
    return true;
}

但是正如您所看到的,注释掉的行提出了一个挑战:是否可以恢复正则表达式对象的原始模式?

显然有一种解决方法是提供原始模式字符串(而不是或旁边)正则表达式对象,然后使用它。但我当然希望不需要包含额外的工作来在每次调用此函数时重新创建正则表达式对象(每次调用函数时重新定位模式时的成本)或者将正则表达式模式与正则表达式对象(容易出现拼写错误和错误,除非我提供一个包装器,为我做这个,这不方便)。

我在Ubuntu 14.04上使用GCC 4.9.2。


4022
2018-06-22 22:23


起源

@ Jarod42:那个(即 回答)已经在一个 回答 为什么要把它写成一个 评论? :-( - Lightness Races in Orbit


答案:


boost::basic_regex 对象有一个 str() 返回用于构造正则表达式的字符串(的副本)的函数。 (他们也提供 begin() 和 end() 将迭代器返回到字符序列的接口,以及内省捕获子表达式的机制。)

这些接口在最初的TR1正则表达式标准化提案中,但在采用后于2003年被删除 n1499:简化basic_regex中的接口,我引用它:

basic_regex不应保留其初始化程序的副本

basic_regex 模板有一个成员函数 str 它返回一个字符串对象,该对象包含用于初始化的文本 basic_regex 对象...虽然查看初始化字符串可能偶尔会有用,但如果您不使用它,我们应该应用您不支付的规则。就像 fstream 对象不带有它们打开的文件名, basic_regex 对象不应随身携带初始化文本。如果有人需要跟踪该文本,他们可以编写一个包含文本和文本的类 basic_regex 目的。


7
2018-06-22 22:59



C ++不想提供类似Java的toString基础设施,这被证明是有帮助的,这很可悲。 - user1633272


根据标准 N4431  §28.8/ 2类模板basic_regex [re.regex](强调我的): 

特殊类型的对象 basic_regex 负责转换序列 charT 对象   内部代表。未指定此表示形式采用何种形式,以及如何访问它   对正则表达式进行操作的算法。 [ 注意: 实现通常会将一些函数模板声明为 basic_regex 为了达成这个 - 结束说明 ]

就这样 basic_regex 对象不需要在内部保留原始字符序列。

因此,您必须在创建时存储字符序列 regex。例如:

struct RegexPattern {
  std::string pattern;
  std::regex  reg;
};
...
bool validate_content(const std::string & str, const RegexPattern & pattern, std::vector<std::string> & errors) {
    if(false == std::regex_match(str, pattern.reg)) {
        std::stringstream error_str;
        error_str << "Pattern match failure: " << pattern.pattern << ", content: " << str;
        errors.push_back(error_str.str());
        return false;
    }
    return true;
}

另一个更优雅的解决方案 @Praetorian 但效率低一些(我没有对两个版本进行基准测试,因此我不确定)。将保留模式字符串并将其作为输入参数传递给函数 validate_content 并创造 regex 对象内部,如下所示:

bool validate_content(const std::string & str, const string & pattern, std::vector<std::string> & errors) {
    std::regex reg(pattern);
    if(false == std::regex_match(str, reg)) {
        std::stringstream error_str;
        error_str << "Pattern match failure: " << pattern << ", content: " << str;
        errors.push_back(error_str.str());
        return false;
    }
    return true;
}

6
2018-06-22 22:45



这是完全有意义的事情之一,不应该改变,但只是 真 烦人。 - Lightness Races in Orbit
@LightnessRacesinOrbit我完全同意。 - 101010
另一个选择,取决于是否 regex 模式需要在其他地方可用,将用于 validate_content 拿一个 std::string 包含模式的参数,并构造 regex 本地。 - Praetorian
这可能就是我要做的。 - Lightness Races in Orbit
很公平,如果它被召唤了很多,那么我就不会这样做。 :)无论哪种方式,我认为你在这里拥有你需要的一切。好极了! - Lightness Races in Orbit