std :: regex转义文件路径

时间:2016-08-30 13:30:51

标签: c++ regex string c++11

我创建一个std::regex(__FILE__)字符串作为单元测试的一部分,它检查一些打印文件名的异常输出。

在Windows上,它失败了:

  

regex_error(error_escape):表达式包含无效的转义字符或尾随转义。

因为__FILE__宏扩展包含未转义的反斜杠。

是否有更优雅的方法来逃避反斜杠而不是循环生成的字符串(即使用std算法或某些std::string函数)?

3 个答案:

答案 0 :(得分:1)

修改

最后,我转到@AdrianMcCarthy的more robust approach

这是我解决问题的不雅方法,万一有人偶然发现这个问题,实际上是在寻找解决方法:

std::string escapeBackslashes(const std::string& s)
{
    std::string out;

    for (auto c : s)
    {
        out += c; 
        if (c == '\\') 
            out += c;
    }

    return out;
}

然后

std::regex(escapeBackslashes(__FILE__));

这是O(N),这可能和你在这里做的一样好,但涉及很多字符串复制,我认为这并不是绝对必要的。

答案 1 :(得分:1)

以下是polymapper

它需要一个带有元素的操作并返回一个范围,"映射操作"。

它生成一个接收容器的函数对象,并应用"映射操作"每个元素。它返回与容器相同的类型,其中每个元素都通过" map操作"进行扩展/收缩。

template<class Op>
auto polymapper( Op&& op ) {
  return [op=std::forward<Op>(op)](auto&& r) {
    using std::begin;
    using R=std::decay_t<decltype(r)>;
    using iterator = decltype( begin(r) );
    using T = typename std::iterator_traits<iterator>::value_type;
    std::vector<T> data;
    for (auto&& e:decltype(r)(r)) {
      for (auto&& out:op(e)) {
        data.push_back(out);
      }
    }
    return R{ data.begin(), data.end() };
  };
}

以下是escape_stuff

auto escape_stuff = polymapper([](char c)->std::vector<char> {
  if (c != '\\') return {c};
  else return {c,c};
});

live example

int main() {
  std::cout << escape_stuff(std::string(__FILE__)) << "\n";
}

这种方法的优点是可以解决弄乱容器内脏的问题。你编写的代码与字符或元素混淆,整体逻辑不是你的问题。

缺点是polymapper有点奇怪,并且完成了不必要的内存分配。 (这些可以优化,但这会使代码更复杂)。

答案 2 :(得分:1)

文件路径可以包含许多在正则表达式模式中具有特殊含义的字符。在一般情况下,仅仅反转反斜杠不足以进行强大的检查。

即使是简单的路径,如C:\Program Files (x86)\Vendor\Product\app.exe,也包含几个特殊字符。如果要将其转换为正则表达式(或正则表达式的一部分),则不仅需要转义反斜杠,还要转义括号和句点(点)。

幸运的是,我们可以使用更正则的表达式解决正则表达式问题:

std::string EscapeForRegularExpression(const std::string &s) {
  static const std::regex metacharacters(R"([\.\^\$\-\+\(\)\[\]\{\}\|\?\*)");
  return std::regex_replace(s, metacharacters, "\\$&");
}

(文件路径不能包含*?,但我已将它们包含在内以保持此功能的通用性。)

如果你不遵守&#34;没有原始循环&#34;准则,一个可能更快的实现将避免正则表达式:

std::string EscapeForRegularExpression(const std::string &s) {
  static const char metacharacters[] = R"(\.^$-+()[]{}|?*)";
  std::string out;
  out.reserve(s.size());
  for (auto ch : s) {
    if (std::strchr(metacharacters, ch))
      out.push_back('\\');
    out.push_back(ch);
  }
  return out;
}

尽管循环增加了一些混乱,但这种方法允许我们在metacharacters的定义上放弃一个转义级别,这是对正则表达式版本的可读性胜利。