2014年5月4日09:03从http://code.google.com/p/febird/wiki/MultiRegexMatch更新至最新版

Introduction

This Multiple Regex Matching solution includes two parts:

  • An offline multiple regex builder application: regex_builder
    1. regex_builder build multiple regex into a DFA file
    2. if using binary mode,generate an optional binMeta text file describe the regex Meta info

  • An online multiple regex matching API
    1. Use the general API load the DFA built by regex_builder
    2. Construct theMultiRegexFullMatchobject from the DFA
    3. Construct theMultiRegexSubMatch,if the submatch capture is required
      • Note: This algorithm Could only capture submatch for one-pass regex
  • This algorithm is very efficient for large number(such as 1,000,000) of regex recognition,a shinning example is query classification
  • This algorithm Could be regarded as a generic Key-Value map,which Key is a regular expression

介绍

这个程序包含一个非常高效的算法,用来匹配多个正则表达式。经过预处理,仅用 O(n) 的时间复杂度,就可以识别出一个输入字符串(长度为n)能匹配哪些(可能是多个)正则表达式。算法的详细内容可参见:

  1. 多正则表达式匹配(Multiple Regular Expression Matching)
  2. 多正则表达式匹配(Multiple Regular Expression Matching) 中的动态 DFA 算法

作为一个完整的解决方案,这个程序包括两部分:

  • 一个离线 Build 程序:regex_build
    1. regex_build 会把输入的正则表达式编译成一个 DFA ,正则表达式的编译使用了 re2 的前端 Parser
    2. 如果使用二进制模式,还会生成一个 binMeta 文本文件,用来描述 DFA 的元信息
      • 该文件生成后不可被更改,否则会产生未定义行为
      • 目前应该首选二进制模式

  • 一个动态库,提供匹配接口
    1. 从 (regex_build生成的) DFA 文件 和 binMeta(二进制模式) 文件 加载 并 创建出 用来执行匹配 的 对象
    2. 在二进制模式下,构造 MultiRegexFullMatch 对象执行全匹配,此时不获取 !Submatch,仅返回能匹配上的正则表达式 ID:MultiRegexFullMatch示例程序
      • FullMatch 匹配完成与google.re2.set相同的功能,但效率要高得多
      • 性能测试:re2bench/setmatch.cpp使用 re2.set,产生与MultiRegexFullMatch示例程序相同格式的输出,以做比对
    3. 在二进制模式下,构造 MultiRegexSubmatch 对象执行匹配:MultiRegexSubmatch示例程序
      • MultiRegexSubmatch 仅能获取 one-pass 正则的 submatch
      • one-pass 正则的判断直接调用了re2 的判断函数 IsOnePass
        • 很不幸,该函数会将正则表达式从([^到]+)到([^怎]+)怎么走判为非 one-pass,但实际上,在 unicode 字符集内,它的确是 one-pass,只是 re2 的底层引擎是基于字节的,所以它认不出来
        • 如果你愿意冒险,regex_build 给你一个选择,将所有的正则表达式标为 one-pass,MultiRegexSubmatch::match_utf8 在搜索完之后,会按 utf8 编码规则做一个边界修正,就可以正确提取出从([^到]+)到([^怎]+)怎么走中的 submatch 了
    • 该程序对大规模的规则系统(例如100万个正则表达式)会非常有用,比如query分类

    Compile

    $ cd febird-trunk
    $ make -C tools/regex
    $ ll tools/regex/*/*.exe
    -rwxrwxrwx 1 leipeng leipeng 15M 2013-11-02 15:41:54 tools/regex/dbg/regex_build.exe
    -rwxrwxrwx 1 leipeng leipeng 26M 2013-11-02 15:42:06 tools/regex/rls/regex_build.exe

    regex_builder 使用方法

    regex_builder.exe 将很多个正则表达式 offline build成一个DFA文件,online程序使用时,先加载DFA文件,当匹配文本时,可以获知匹配到了哪些正则表达式,同一个文本可能匹配多个正则表达式。

    匹配接口分文本接口于二进制接口两种,目前二进制接口已经有了很友好的封装,推荐使用。

    文本接口的使用方法与之前的DFA词表完全相同(match_key接口)。

    该程序使用 re2 的parser前端,生成 febird 自己的 DFA 文件

    命令行选项与参数

    命令行: regex_build.exe Options

    Options 命令行选项 说明
    -i Regex.txt 输入的正则表达式描述文件,也可以通过标准输入传递,该参数优先于标准输入
    -O regex_dfa_file 生成的自动机文件
    -a 从所有位置开始匹配,相当于在所有正则表达式之前加.*,这会加快匹配速度,因为不需要重新从输入文本的每个位置开始搜索,
    但会大大增加内存用量(20倍以上),build消耗的时间也会显著增加
    -A 在所有正则表达式合并之后加.*,仅用于测试
    -b binMeta_file 生成 binMeta_file,是在 Binary 模式下获取 Submatch 时使用的元信息,使用二进制匹配接口时,必须加这个选项
    -g 为每个正则表达式生成三个 dot 文件,该文件用来可视化正则表达式自动机的状态图NFA/DFA/MinimizedDFA
    -G 生成整个DFA的dot文件,通常情况下,该文件会很大
    -L 不使用UTF8,使用latin1;不加该选项时(默认情况)使用的是UTF8
    -d delimiter 将正则表达式看做Key,delimiter表示key,value之间的分隔符, build时会将该字符从正则表达式的DFA中删除,
    因此目标文本中出现此字符时,匹配就会失败。默认是 256,在 byte 取值范围之外
    -c conflict_report_file 当同一个文本会被多个正则表达式匹配时,此时称为冲突,该选项将冲突的正则表达式的id写到conflict_report_file
    很多时候冲突是不可避免的,但是,根据 confict_report_file,可以修改正则表达式,尽可能减小冲突的可能性
    -s 捕获 submatch,也就是 () 中的部分,默认情况下不捕获 submatch
    -t dfa_type 默认dfa_type=d,表示 DenseDFA,专为正则表达式优化的DFA
    d以外的其它字符,表示DFA类型为一般DFA,主要为词表DFA优化
    -D 构建动态DFA以节省内存和构建时间,在某些情况下,构建完整DFA甚至是不可能的,
    如果没指定该选项,该程序会尝试用100倍于所有正则表达式的内存,如果失败,仍然会构建动态DFA
    -I 正则表达式忽略大小写

    关于 -d 选项

    一开始 febird DFA 通过 match_key 接口来实现正则表达式匹配,必须在 byte 的取值范围 [0,256) 之间取一个作为分隔符。后来,经过仔细考虑,通过扩充自动机的字符集( r1303),从而 delimeter 可以在 [0,256) 之外取值,于是就不再需要从 [0,256) 取一个特殊值来作为分隔符。
    这样,正则表达式匹配就可以有更广的适用范围。另一方面,表面上看,似乎去除一个特殊byte值作为delimeter会影响二进制模式的匹配,其实一点也不会。正则表达式相当于key,正则表达式的 id 相当于是 value,delimeter 不能出现在 key 中,但可以出现在 value 中,从而,value可以是任意二进制数据。实际上,二进制匹配接口的实现是先于 r1303的。
    于是,现在,只有在当 你知道你在干什么的时候,才需要指定 -d delim选项,否则,一定不要用 -d

    输入文件Regex.txt 的格式

    regexp \t id

    第一列是正则表达式,如果行首字符是*,表示忽略该正则表达式的 one pass 属性,无条件获取 submatch,用*做标志的原因是以*开头的正则表达式是非法的正则,从而不会引发歧义,也不会减少表达能力。

    第二列是正则表达式的id,该id可以是任意字符串,用来标识这条规则。多个正则表达式可以有相同的id,此时等效于将多个正则表达式或起来放在一行。

    一个示例的Regex.txt

    a.*b  a-dot-star-b
    a[a-f]*b  1
    a]*([a-c]*)+[bc]+  2
    a(1|234)[ab][ab]{5}  3
    a([0-3a-dx-z,})[2cdxy]*abc 4
    [358][9])[8}  mobile-phone-num
    \+86-(} china-mobile\d{}\.\d} ip_address
    antidisestablishmentarianism  一般人能看懂的最长单词

    非常重要!注意事项!

    谨慎使用.*,特别是当.*处于正则表达式开头时

    普通字符串(不包括正则表达式的元字符)也可以放进Regex.txt,可以为所有普通字符串赋予一个相同的id,这样就将正则表达式和普通字符串build到同一个DFA中了,普通字符串在DFA中占的空间相对要小得多,如果普通字符串很多,可以尝试用 -t x选项,看生成的DFA文件是否更小。

    匹配接口: 二进制模式

    要使用二进制接口,在使用 regex_build.exe 创建自动机时,必须加 -b bin_Meta_file 选项

    MultiRegexFullMatch

    参考MultiRegexFullMatch示例程序

    MultiRegexSubMatch

    参考MultiRegexSubmatch示例程序

    匹配任意位置

    如果要匹配任意位置,需要自己每次前进一个(utf8)字符,重新开始匹配(match_and_print):

     #include <febird/util/unicode_iterator.hpp> // for febird::utf8_byte_count
     // ......
     // ...
       fstring text = some string;
       for (size_t off = 0; off < text.size(); ) {
         fstring suffix(text.begin() + off,text.end());
         match_and_print(sub,suffix);
         off += febird::utf8_byte_count(text[off]);
       }

    匹配接口: 文本模式

    文本接口是在创建该算法的原型时使用的,不推荐使用,除非作为 Demo 或者——你知道你在干什么!

    匹配接口使用方法可以参考DFA_Interface::match_key 示例程序

    直接去 febird-trunk/samples/automata/abstract_api/ 目录运行 make即可编译,编译输出在 rls 和 dbg 目录下

    编译出来的 match_key 程序可用来测验匹配(match_key程序使用的 delimiter是 \t ):

    febird-trunk/samples/automata/abstract_api/rls/match_key -d -i samples.dfa abcccb 输出:

    abcccb ----------
    ab          value: idx=00000000 str1
    ab          value00000001 str2
    ab          value00000002 str=a-b
    abc         value2
    abcc         value2
    abccc        value2
    abcccb        value1
    abcccb        value-b

    输出的 str=1 str=2 str= a-dot-star-b就是匹配到了id为1、2、a-dot-star-b的正则表达式

    使用 match_key 接口,正则表达式匹配和词典匹配就完全相同。

    多正则表达式匹配工具 的用法的更多相关文章

    1. HTML5数字输入仅接受整数的实现代码

      这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    2. ios – 伞框架

      错误.应用程序,通常位于…错误仍然存在你也可以在这里添加(子)框架的路径.

    3. 如何在xcode 6中构建32位和64位的单二进制文件

      我已经遵循this堆栈溢出解决方案,但即使我得到低于警告.我已经选择虽然我得到了警告.请帮帮我.谢谢.解决方法有同样的问题.看起来将’arm64’添加到ValidArchitectures解决了它.

    4. ios – 使用大写符号在字符串swift中获取URL的正则表达式

      我尝试在文本中获取URL.所以,在此之前,我使用了这样一个表达式:但是当用户输入带有大写符号的URL时(例如Http://Google.com,它与它不匹配)我遇到了问题.我试过了:但什么都没发生.解决方法您可以使用正则表达式中的i内联标志关闭区分大小写,有关可用正则表达式功能的详细信息,请参阅FoundationFrameworkReference.(?ismwx-ismwx)Flagsetti

    5. ios – 将二进制文件上传到Apple的iTunesConnect时会发生什么?

      我问,因为:它可能指向我们可以做的事情来加快这个过程.大约一年前,这个过程从“缓慢,因为苹果的服务器功率不足”变得“非常缓慢,因为苹果公司使用的带宽是发送二进制文件所需带宽的3倍”.例如我最近提交了一个90Mb应用程序,Xcode4将超过350Mb的数据上传到Apple.例如刚才我提交了一个8Mb的二进制文件,Xcode4将超过40Mb的数据上传到Apple.最近上传者有了很大的改进.但我想知道:苹果在上传期间实际上做了什么?

    6. ios – iTunes Connect警告:“您的二进制文件不支持iPad”

      我刚刚将一个新的二进制文件上传到iTunesConnect,并将其添加到iOS版本的新版本.添加二进制文件并保存更改后,iTunesConnect会显示警告消息:“您的二进制文件不支持iPad,iPad的屏幕截图或应用视频预览将不会显示在AppStore上.”Xcode项目是使用Cordova3CLI生成的;自从应用从Cordova2迁移以来,上传的二进制文件是第一个Cordova3版本.该应用程

    7. ios – 二进制无效,二进制文件缺少体系结构[arm64]

      没有足够的信誉发布图像,请搜索“TimT”作为他的回复.更新:已经修复“是的,最近有一个修复程序应用于服务器,每个人都应该能够再次提交32位应用程序.–由TimT在同一个线程.我再次尝试,一切都很好.

    8. ios – 不能检查CGPoint是否不等于CGPointZero

      我有一个CGPoint在UIView类中声明,在我的viewController中,我尝试检查CGPoint是否不等于CGPointZero,但是我收到这个错误:二进制表达式(‘CGPoint'(又名’structCGPoint’)’和’CGPoint“)这是if语句:错误指向!=和我不知道为什么它给我一个错误.操纵杆是UIView类,CGPoint速度是这样声明的:@property(非原子)C

    9. 通用定制iOS框架使用Xcode 6.4

      我已经使用Xcode6创建了一个自定义的iOS框架.我尝试了许多脚本来使框架通用(用于模拟器和设备).但是它们都不适用于我.请告诉我一种方法来为iOS创建一个自定义的通用框架Xcode6.解决方法要通过终端将两个二进制文件合并成通用二进制文件:首先编译器件二进制,然后分别编译模拟器二进制.找到这两个二进制文件.如果你想检查哪些架构被编译成每个,你可以在终端中运行这个命令:lipo-info/pat

    10. ios – 如何在Swift 3中使用正则表达式?

      解决方法我相信.当没有其他选项适用时,将使用.allZeros.因此,使用Swift3,您可以传递一个空的选项列表或省略options参数,因为它默认为无选项:要么请注意,在Swift3中,您不再使用error参数.它现在抛出.

    随机推荐

    1. 法国电话号码的正则表达式

      我正在尝试实施一个正则表达式,允许我检查一个号码是否是一个有效的法国电话号码.一定是这样的:要么:这是我实施的但是错了……

    2. 正则表达式 – perl分裂奇怪的行为

      PSperl是5.18.0问题是量词*允许零空间,你必须使用,这意味着1或更多.请注意,F和O之间的空间正好为零.

    3. 正则表达式 – 正则表达式大于和小于

      我想匹配以下任何一个字符:或=或=.这个似乎不起作用:[/]试试这个:它匹配可选地后跟=,或者只是=自身.

    4. 如何使用正则表达式用空格替换字符之间的短划线

      我想用正则表达式替换出现在带空格的字母之间的短划线.例如,用abcd替换ab-cd以下匹配字符–字符序列,但也替换字符[即ab-cd导致d,而不是abcd,因为我希望]我如何适应以上只能取代–部分?

    5. 正则表达式 – /bb | [^ b] {2} /它是如何工作的?

      有人可以解释一下吗?我在t-shirt上看到了这个:它似乎在说:“成为或不成为”怎么样?我好像没找到’e’?

    6. 正则表达式 – 在Scala中验证电子邮件一行

      在我的代码中添加简单的电子邮件验证,我创建了以下函数:这将传递像bob@testmymail.com这样的电子邮件和bobtestmymail.com之类的失败邮件,但是带有空格字符的邮件会漏掉,就像bob@testmymail也会返回true.我可能在这里很傻……当我测试你的正则表达式并且它正在捕捉简单的电子邮件时,我检查了你的代码并看到你正在使用findFirstIn.我相信这是你的问题.findFirstIn将跳转所有空格,直到它匹配字符串中任何位置的某个序列.我相信在你的情况下,最好使用unapp

    7. 正则表达式对小字符串的暴力

      在测试小字符串时,使用正则表达式会带来性能上的好处,还是会强制它们更快?不会通过检查给定字符串的字符是否在指定范围内比使用正则表达式更快来强制它们吗?

    8. 正则表达式 – 为什么`stoutest`不是有效的正则表达式?

      isthedelimiter,thenthematch-only-onceruleof?PATTERN?

    9. 正则表达式 – 替换..与.在R

      我怎样才能替换..我尝试过类似的东西:但它并不像我希望的那样有效.尝试添加fixed=T.

    10. 正则表达式 – 如何在字符串中的特定位置添加字符?

      我正在使用记事本,并希望使用正则表达式替换在字符串中的特定位置插入一个字符.例如,在每行的第6位插入一个逗号是什么意思?如果要在第六个字符后添加字符,请使用搜索和更换从技术上讲,这将用MatchGroup1替换每行的前6个字符,后跟逗号.

    返回
    顶部