保存/序列化提升或标准正则表达式

Save/Serialize boost or std regexes

本文关键字:标准 正则表达式 序列化 保存      更新时间:2023-10-16

是否可以序列化/反序列化和保存/加载正则表达式到文件/从文件加载?

我们

有一个非常耗时的过程来构建一些正则表达式,我想知道我们是否可以通过保存和加载它们来节省一些时间。

不,这可能是不可能的,因为它无论如何都需要您重新编译正则表达式。

但是,如果使用 boost::xpressive,则可以在编译时通过正则表达式的表达式模板构造来编译正则表达式。这将使正则表达式编译时间完全消失。

提升压抑

但是,使用

过多时间的真正原因几乎可以肯定是您通过使用回溯正则表达式引擎不正确地使用正则表达式,即 IE。

RE2 是一个传统的自动机正则表达式引擎,它不使用回溯,而是直接构造 NFA 或 DFA。如果您不使用反向引用或许多基于非正则表达式的"特征",则在许多极端情况下,使用 RE2 的速度将提高一个数量级。

如果您正在使用这些功能,您应该意识到它们将严格控制您的匹配速度,并且几乎可以肯定它们是您试图消除的速度变慢的主要原因。

这很难用 boost/stl 正则表达式类来实现。 问题是所述类的内部结构。

  1. 实现如何存储类属性?按地址、值?
  2. 编译器引入了哪些附加填充(如果有)?
  3. 是否存在任何平台对齐问题?
  4. 等。。。

以帮助说明问题的难度。 尝试查找C++类实例的大小。

regex pattern( "^Corvusoft$" );
printf( "%lun", sizeof( pattern ) );  //32
regex alternative( "C" );
printf( "%lun", sizeof( alternative ) );  //32

替代解决方案 1

在构建时创建包含所需正则表达式和链接的库,或通过 dlopen API 动态打开和加载库。 然后,您将使用诸如prelink之类的工具来确保它们已经在内存中;预编译。

替代解决方案 2

使用 C 正则表达式.h。

您可以遍历 regex_t POD 结构并将其内容写入二进制或内存映射文件。 稍后,您可以将这些数据值映射回新的regex_t结构,完全避免重新编译正则表达式。

#include <regex.h>
regex_t pattern;
int result = 0;
result = regcomp( &pattern, "^Corvusoft$", 0 );
if ( result )
{
   fprintf( stderr, "Failed to compile regular expression patternn" );
}
TODO: walk structure and write to binary/memory mapped file.

替代解决方案 3

遵循@Alice的建议并使用Boost.Xpressive。

你可以序列化一个 boost::regex:

#include <string>
#include <iostream>
#include <sstream>
#include <boost/regex.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
namespace boost
{
  namespace serialization
  {
    template<class Archive, class charT, class traits>
    inline void save(Archive & ar, 
                     const boost::basic_regex<charT, traits> & t, 
                     const unsigned int /* file_version */)
    {
      std::basic_string<charT> str = t.str();
      typename boost::basic_regex<charT, traits>::flag_type flags = t.flags();
//      typename boost::basic_regex<charT, traits>::locale_type loc = t.getloc();
      ar & str;
      ar & flags;
//      ar & loc;
    }
    template<class Archive, class charT, class traits>
    inline void load(Archive & ar, 
                     boost::basic_regex<charT, traits> & t, 
                     const unsigned int /* file_version */)
    {
      std::basic_string<charT> str;
      typename boost::basic_regex<charT, traits>::flag_type flags;
//      typename boost::basic_regex<charT, traits>::locale_type loc;
      ar & str;
      ar & flags;
//      ar & loc;
      t.assign(str, flags);
//      t.imbue(loc);
    }
    template<class Archive, class charT, class traits>
    inline void serialize(Archive & ar, 
                          boost::basic_regex<charT, traits> & t, 
                          const unsigned int file_version)
    {
      boost::serialization::split_free(ar, t, file_version);
    }
  }
}
int main(int argc, char ** argv)
{
  std::stringstream os;
  {
    boost::regex re("<a\s+href="([\-:\w\d\.\/]+)">");
    boost::archive::text_oarchive oar(os);
    oar & re;
  }
  os.seekg(std::ios_base::beg);
  boost::regex re;
  boost::cmatch matches;
  boost::archive::text_iarchive iar(os);
  iar & re;
  boost::regex_search("<a href="https://stackoverflow.com/questions/18752807/save-serialize-boost-or-std-regexes">example</a>", matches, re);
  std::cout << matches[1] << std::endl;
}

但这并不意味着与从字符串重建正则表达式相比,您将获得任何性能提升。

注意:为了简单起见,我省略了 std::locale 的东西