正则表达式的实现,可以处理机器生成的正则表达式的:*非回溯*,O(N)?(Regex impleme

2019-06-26 17:48发布

编辑2:为什么这仍然是重要的一个实际演示,没有比计算器自己的正则表达式,停电造成今日(二零一六年七月二十零日) !

编辑:这个问题有相当大的变化,因为我第一次问它。 请参阅下面的两个快速+兼容,但不完全全功能的实现。 如果你知道更多,更好的实现方式的,请注明他们,仍然不是一个理想的实现来呢!

我在哪里可以找到可靠快速的正则表达式实现?

有谁知道一个正常的非回溯System.Text.RegularExpressions回溯)线性时间的正则表达式实施无论是对.NET或本地和.NET合理使用吗? 为了有用,那就需要:

  • 具有O(m * n个),其中m是正则表达式的长度的正则表达式评估的最坏情况下的时间复杂度,并且n将输入的长度。
  • O(n)的正常时间复杂度 ,因为几乎没有正则表达式实际上触发指数状态空间,或者,如果他们能做到,只有在输入的一分钟子集这样做。
  • 有一个合理的施工速度 (即没有潜在的指数DFA的)
  • 意为通过人类,不是数学家用-例如,我不想重新实现Unicode字符类:.NET或PCRE风格字符类是一个加号。

奖励积分:

  • 加分实用性如果它实现基于堆栈的特征,其让它处理在消耗O(N + M)存储器,而不是O(M)存储器为代价嵌套
  • 对于任何一个捕捉子表达式更换奖励积分(如果有可能的子表达式匹配一个指数,然后枚举所有的人本质上是指数-但列举的前几个不应该是,同样的替代)。 您可以通过使用其他的,所以有一方是足够的解决办法缺少任一功能。
  • 用于治疗正则表达式作为第一类值 lotsa奖励积分(这样你就可以采取集,交集,级联,否定-尤其是否定和路口那些是很难通过正则表达式定义的字符串操作做)
  • 在无限流懒惰匹配 ,即匹配没有把它全部在内存中是一个加号。 如果流不支持在单次寻找,捕捉子表达式和/或更换不(一般)成为可能。
  • 反向引用都出来了 ,他们根本不可靠; 即总能表现出给定的病理输入的情况下指数行为。

这样的算法存在(这是基本的自动机理论...) -但是否有任何实际可用的实现从.NET访问?

背景:(你可以跳过此)

我喜欢用正则表达式的快速和肮脏的文本清理工作,但我已经多次碰到哪里被Perl / JAVA / Python中的常见回溯NFA implemtation / .NET显示指数特性的问题。 这些情况都是不幸相当容易,只要你自动开始产生正则表达式触发。 例如,在一个非常简单的例子,如果你把一本字典,把它变成一个正则表达式,预计可怕的性能 - 当你匹配相同前缀的正则表达式之间交替即使非指数性能变得非常差。

对于为什么存在更好的实现,并自60年代有一个快速的概述,见正则表达式匹配可以是简单和快速 。

不太实用的选择:

  • 近乎理想FSA工具 。 可以编译正则表达式快速DFA的NFA +公司的C实现,允许换能器(!)也拥有一流的正则表达式(封装耶!),包括语法路口参数化。 但它在序言中 ......(为什么是一些与这种在主流语言???不可用的实用功能)
  • 速度快,但不切实际的 :一个完整的分析程序,如优秀ANTLR普遍支持可靠快速的正则表达式。 然而,ANTLR的语法更加冗长,当然允许,可能无法生成有效的解析器,所以你需要找到一些安全的子集的构建。

良好的实现:

  • RE2 -谷歌的开源库,旨在为合理PCRE兼容性减去反向引用。 我想,这是继Plan9的正则表达式11b的UNIX端口,给笔者。
  • TRE -也大多与PCRE兼容,甚至做反向引用,但使用这些你失去了速度的保证。 而且它有一个大型漂亮的近似匹配模式!

不幸的是这两种实现是C ++,并且需要互操作,从.NET中使用。

Answer 1:

首先,你的建议是可能的,你当然知道你的主题。 你也知道,不使用回引用实现的权衡是内存。 如果你能够控制自己的环境足够这可能是一个合理的做法。

我会继续之前发表评论的唯一的事情是,我会鼓励你用怀疑正则表达式的选择。 你显然更熟悉你的特定问题和你试图解决这样只有你能回答这个问题的。 我不认为ANTLR将是一个不错的选择; 然而,家庭酿造规则引擎(如果包括但不限于)可以高度调节到您的特定需求。 这一切都取决于您的具体问题。

对于那些读这篇文章,“切中要害”,这里是一些背景阅读:

  • 正则表达式匹配可以是简单和快速

来自同一个站点,有许多实现这个页面上链接 。

上述文章的整个讨论的要点是,最好的答案就是同时使用。 为此,广泛应用的只有实现我所知道的是由TCL语言使用的一个。 据我所知,最初是由亨利·斯宾塞书面和它使用这种混合的方法。 已经有它移植到AC库中的一些尝试,虽然我不知道任何被广泛使用。 沃尔特·沃尔多的和托马斯·拉克的都提到与此挂钩 。 还提到了Boost库 ,虽然我不知道的执行。 您还可以看看TCL代码本身(从链接他们的网站 ),并从那里工作。

总之,我会跟去TRE或计划9 ,因为这些都是积极支持。

显然,这些都不是C#/。NET和我不知道一个是的。



Answer 2:

如果你能处理使用不安全的代码(和发牌的问题),你可能需要从实现这个TRE窗口 。

你也许能够直接与P / Invoke并以下显式布局结构使用:

typedef int regoff_t;
typedef struct {
  size_t re_nsub;  /* Number of parenthesized subexpressions. */
  void *value;     /* For internal use only. */
} regex_t;

typedef struct {
  regoff_t rm_so;
  regoff_t rm_eo;
} regmatch_t;


typedef enum {
  REG_OK = 0,       /* No error. */
  /* POSIX regcomp() return error codes.  (In the order listed in the
     standard.)  */
  REG_NOMATCH,      /* No match. */
  REG_BADPAT,       /* Invalid regexp. */
  REG_ECOLLATE,     /* Unknown collating element. */
  REG_ECTYPE,       /* Unknown character class name. */
  REG_EESCAPE,      /* Trailing backslash. */
  REG_ESUBREG,      /* Invalid back reference. */
  REG_EBRACK,       /* "[]" imbalance */
  REG_EPAREN,       /* "\(\)" or "()" imbalance */
  REG_EBRACE,       /* "\{\}" or "{}" imbalance */
  REG_BADBR,        /* Invalid content of {} */
  REG_ERANGE,       /* Invalid use of range operator */
  REG_ESPACE,       /* Out of memory.  */
  REG_BADRPT            /* Invalid use of repetition operators. */
} reg_errcode_t;

然后使用能够处理字符串嵌入的null出口(宽字符的支持)

/* Versions with a maximum length argument and therefore the capability to
   handle null characters in the middle of the strings (not in POSIX.2). */
int regwncomp(regex_t *preg, const wchar_t *regex, size_t len, int cflags);

int regwnexec(const regex_t *preg, const wchar_t *string, size_t len,
      size_t nmatch, regmatch_t pmatch[], int eflags);

通过更容易翻译和更大的灵活性(我当然会建议,如果您熟悉C ++ / CLI,这是明智的)一个C ++ / CLI的解决方案或者包裹。



Answer 3:

我在哪里可以找到稳健快速的正则表达式实现?

你不能。

总要有人说,答案给定的限制,这个问题肯定是你不能 - 它不太可能,你会发现符合您的约束的实现。

顺便说一句,我相信你已经尝试过是这样,但你有没有编译正则表达式(与输出到装配选项) - 我这样说是因为:

如果你有短字符串的正则表达式复杂,数百万测试



Answer 4:

考虑一下的DFA从正则表达式创建:

你开始用正则表达式。 每个操作(concat,则联合,克林闭合)表示在NFA状态之间的转变。 得到的DFA的状态代表了NFA状态的发电机组。 在NFA的状态是线性正则表达式的大小,因此,DFA的状态是指数的正则表达式的大小。

所以,你的第一个约束,

具有的O的正则表达式的评估(m * n个),其中m是正则表达式的长度的最坏情况下的时间复杂度,并且n将输入的长度

是不可能的。 正则表达式需要编译到2 ^ M-状态DFA(最坏情况),这将不在线性时间内完成。

这始终是与所有,但最简单的正则表达式的情况。 那些是如此简单,你可以只写一个快速的.contains表达更容易。



Answer 5:

快速注释:仅仅因为你可以通过多个状态模拟,并不意味着你没有做的NFA-DFA转换的工作模拟DFA建设。 所不同的是,你是分布在搜索本身的努力。 即,最差情况下的性能保持不变。



文章来源: Regex implementation that can handle machine-generated regex's: *non-backtracking*, O(n)?