<regex> std :: regex等同于Qt的QRegularExpression :: isValid()而不触发异常

时间:2017-06-26 22:30:42

标签: c++ regex exception-handling std c++17

我正在尝试将一些正则表达式工具从Qt迁移到std。在Qt中,我可以在使用isValid()

之前测试正则表达式是否有效

在标准<regex>中,我没有办法做到这一点。所以现在,我有try/catch块使用用户提供的正则表达式生成正则表达式,然后尝试将其与1-char字符串匹配,以快速触发std::regex_error异常,而不加载实际的搜索字符串(s)所以我可以提前退出。这是一个肮脏的黑客IMO,但我不确定是否有更好的方法来使用std::regex有效地测试它们。我基本上试图避免在使用工具自动输入时捕获和处理异常的性能障碍。

try
{
    const std::regex regex_exception_trigger(regex_string);
    std::smatch stability_match;
    const std::string test_string = "0";
    if (std::regex_search(test_string.begin(), test_string.end(), stability_match, regex_exception_trigger)) {}
}
catch (std::regex_error &re) { std::cerr << re.what() << std::endl; print_help(); return exit_enum::BAD_REGEX;  }

2 个答案:

答案 0 :(得分:1)

C ++库(尤其是标准库)通常订阅的理念是,如果您有一个类的实例,那么该实例是有效的。因此,如果您尝试构造一个输入错误的类,它将在您构造它时抛出异常,而不是在您尝试使用它时。

这通常很好,因为它清楚地说明了你出错的地方:如果我尝试用错误构造的正则表达式解析一个字符串并且我得到一个例外,那么自然的想法是字符串有问题,不是正则表达式。

您的用例并不适合这个模具,因为C ++标准库假定构造不良的正则表达式是异常的(因此例外)。

如果不抛出异常是很便宜的(例如,如果你不需要抓住任何东西,那么try-catch块的开销很小,但实际上捕获异常可能会很昂贵。如果您希望收到大量错误构造的正则表达式,并且您认为捕获异常会显着影响性能(尽管捕获异常的成本,您仍然可以,所以您应该进行一些测试),您需要考虑在构造正则表达式之前验证正则表达式的另一种工具。

Boost还提供标准库版本所基于的正则表达式库。语法将非常相似。 Boost的版本有一个no_except标志,可以传递给正则表达式构造函数,并将抑制无效字符串中的任何异常。我上面给出的原因大概是为什么这个标志没有包含在标准库版本中。如果您需要此行为,则可以考虑使用Boost版本。

答案 1 :(得分:1)

如果要捕获所有错误,请在try {} catch {} catch {} catch {}序列中执行所有操作。

我将构造从使用中分离出来。

伪代码

std::regex Rx;
bool bIsConstructError = false;

////////////////////////////////////////
bool SetRx( std::string& strRx )
{
   bIsConstructError = false;
   try 
   {
      Rx.assign( "", 0);
      Rx.assign( strRx, 0 );
   }
   catch ( std::regex_error & e )
   {
      bIsConstructError = true;
      return false;
   }
   catch ( std::out_of_range & e )
   {
      bIsConstructError = true;
      return false;
   }
   catch ( std::runtime_error & e )
   {
      bIsConstructError = true;
      return false;
   }
   return true;
}

////////////////////////////////////////
bool  findText( std::string& strTarget )
{
   if ( bIsConstructError )
      return false;

   bool bRet = true;

   std::smatch _M;
   std::string::const_iterator start = strTarget.begin();
   std::string::const_iterator end = strTarget.end();

   try
   {
      if ( regex_search( start, end, _M, Rx, 0 ) )
      {
          // do something
      }
   }
   catch ( std::out_of_range & e )
   {
      bRet = false;
   }
   catch ( std::runtime_error & e )
   {
      bRet = false;
   }
   return bRet;
}