<regex> std::regex 相当于 Qt 的 QRegularExpression::isValid() 不触发异常
<regex> std::regex equivalent to Qt's QRegularExpression::isValid() without triggering exceptions
我正在尝试将一些正则表达式工具从 Qt 迁移到 std。在 Qt 中,我可以在使用 isValid()
之前测试正则表达式是否有效
在 std 的 <regex>
中,我看不到执行此操作的方法。所以现在,我有 try/catch
块使用用户提供的正则表达式制作正则表达式,然后尝试将其与 1 个字符的字符串匹配以快速触发 std::regex_error
异常而不加载实际的搜索字符串(s) 这样我就可以早点退出。这是 IMO 的肮脏 hack,但我不确定是否有更好的方法可以使用 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; }
C++ 库(尤其是标准库)通常认同这样一种理念,即如果您有一个 class 的实例,那么该实例就是有效的。因此,如果您尝试使用错误输入构造 class,它会在您构造它时抛出异常,而不是在您尝试使用它时抛出异常。
这通常很好,因为它清楚地表明了哪里出错了:如果我尝试用错误构造的正则表达式解析字符串并且我得到一个异常,自然而然的想法是字符串,而不是正则表达式。
您的用例不适合这种模式,因为 C++ 标准库假定构造不当的正则表达式是异常的(因此是异常)。
不抛出异常时成本很低(即,如果您不需要捕获任何东西,try-catch
块的开销很小),但实际上捕获异常可能很昂贵。如果您预计会收到很多构造不正确的正则表达式,并且您认为捕获异常会显着影响性能(尽管捕获异常的成本很高,但您仍然可能没问题,所以您应该做一些测试),您需要考虑在构造正则表达式之前验证正则表达式的不同工具。
Boost 还提供了标准库版本所基于的正则表达式库。语法将非常相似。 Boost 的版本有一个 no_except
标志,可以传递给正则表达式构造函数,并将抑制来自无效字符串的任何异常。我上面给出的原因大概是标准库版本中没有包含这个标志的原因。如果您需要这种行为,您可以考虑改用 Boost 版本。
如果您想捕获所有错误,请在 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;
}
我正在尝试将一些正则表达式工具从 Qt 迁移到 std。在 Qt 中,我可以在使用 isValid()
在 std 的 <regex>
中,我看不到执行此操作的方法。所以现在,我有 try/catch
块使用用户提供的正则表达式制作正则表达式,然后尝试将其与 1 个字符的字符串匹配以快速触发 std::regex_error
异常而不加载实际的搜索字符串(s) 这样我就可以早点退出。这是 IMO 的肮脏 hack,但我不确定是否有更好的方法可以使用 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; }
C++ 库(尤其是标准库)通常认同这样一种理念,即如果您有一个 class 的实例,那么该实例就是有效的。因此,如果您尝试使用错误输入构造 class,它会在您构造它时抛出异常,而不是在您尝试使用它时抛出异常。
这通常很好,因为它清楚地表明了哪里出错了:如果我尝试用错误构造的正则表达式解析字符串并且我得到一个异常,自然而然的想法是字符串,而不是正则表达式。
您的用例不适合这种模式,因为 C++ 标准库假定构造不当的正则表达式是异常的(因此是异常)。
不抛出异常时成本很低(即,如果您不需要捕获任何东西,try-catch
块的开销很小),但实际上捕获异常可能很昂贵。如果您预计会收到很多构造不正确的正则表达式,并且您认为捕获异常会显着影响性能(尽管捕获异常的成本很高,但您仍然可能没问题,所以您应该做一些测试),您需要考虑在构造正则表达式之前验证正则表达式的不同工具。
Boost 还提供了标准库版本所基于的正则表达式库。语法将非常相似。 Boost 的版本有一个 no_except
标志,可以传递给正则表达式构造函数,并将抑制来自无效字符串的任何异常。我上面给出的原因大概是标准库版本中没有包含这个标志的原因。如果您需要这种行为,您可以考虑改用 Boost 版本。
如果您想捕获所有错误,请在 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;
}