是否可以对文件进行序列化/反序列化和保存/加载正则表达式?
我们有一个非常耗时的过程来构建一些正则表达式,我想知道我们是否可以通过保存和加载它们来节省一些时间。
不,这可能是不可能的,因为无论如何它都需要您重新编译正则表达式。
但是,如果您使用 boost::xpressive,您可以在编译期间通过正则表达式的表达式模板构造来编译正则表达式。这将使正则表达式编译时间完全消失。
但是,您使用过多时间的真正原因几乎可以肯定是您通过使用回溯正则表达式引擎不正确地使用了正则表达式,即 IE。
RE2是传统的自动机正则表达式引擎,不使用回溯,而是直接构造 NFA 或 DFA。如果您不使用反向引用或许多基于非正则表达式的“功能”,则使用 RE2 将在许多极端情况下显示速度提高一个数量级。
如果您正在使用这些功能,您应该意识到它们将严格控制您的匹配速度,并且几乎可以肯定它们是您寻求消除速度减慢的主要原因。
使用 boost/stl 正则表达式类将很难实现。问题是所述类的内部结构。
帮助说明问题的难度。尝试找出 C++ 类实例的大小。
regex pattern( "^Corvusoft$" );
printf( "%lu\n", sizeof( pattern ) ); //32
regex alternative( "C" );
printf( "%lu\n", sizeof( alternative ) ); //32
替代解决方案 1
在构建期间创建一个包含所需正则表达式和链接的库,或者通过dlopen api动态打开和加载该库。然后,您将使用诸如prelink之类的工具来确保它们已经在内存中;预编译。
替代解决方案 2
使用 C regex.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 pattern\n" );
}
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 内容