减少 std::正则表达式编译时间 C++

Reducing std::regex compile time in C++

本文关键字:时间 C++ 编译 正则表达式 std 减少      更新时间:2023-10-16

我正在使用std::regex r("-?[0-9]*(.[0-9]+)?(e-?[0-9]+)?")来验证数字(整数/定点/浮点)。MWE如下:

#include <iostream>
#include <string>
#include <vector>
#include <regex>
#include <algorithm>
using namespace std;
bool isNumber(string s) {
  // can ignore all whitespace
  s.erase(remove(s.begin(), s.end(), ' '), s.end());
  std::regex r("-?[0-9]*(.[0-9]+)?(e-?[0-9]+)?");
  return regex_match(s, r);
}
int main() {
  std::vector<string> test{
    "3", "-3", // ints
      "1 3", " 13", " 1 3 ", // weird spacing
      "0.1", "-100.123123", "1000.12312", // fixed point
      "1e5", "1e-5", "1.5e-10", "1a.512e4", // floating point
      "a", "1a", "baaa", "1a", // invalid
      "1e--5", "1e-", //invalid
      };
  for (auto t : test) {
    cout.width(20); cout << t << " " << isNumber(t) << endl;
  }
  return 0;
}

注意到与我预期的相比,编译时间相当长:

  • gcc 5.4 -O0 -std=c++11 , 2.3 秒
  • gcc 5.4 -O2 -std=c++11 , 3.4 秒
  • clang++ 3.8 -O0 -std=c++11 , 1.8 秒
  • clang++ 3.8 -O2 -std=c++11 , 3.7 秒

我将其用于在线评委提交,该提交在编译阶段有时间限制。

所以,令人讨厌的问题:

  • 为什么编译时间这么大?我的印象是,当我在 vim/emacs/grep/ack/ag 等(在同一台机器上)中使用正则表达式时,编译花费的时间确实比这少得多。
  • 有没有办法减少正则表达式在C++中的编译时间?

您当然可以通过适当地转义小数点来减轻正则表达式的计算负载: -?[0-9]*(.[0-9]+)?(e-?[0-9]+)? 这当然可以防止您在以下数字上返回误报:"1 3"(不要担心这是一件好事,那是 2 个数字。但是在这种情况下和许多其他情况下,当您屈服于使用正则表达式时,"现在您有 2 个问题"。

使用 istringstream 将为此问题提供更专业、更可靠的解决方案:

bool isNumber(const string& s) {
    long double t;
    istringstream r(s);
    return r >> t >> ws && r.eof();
}

现场示例