【问题标题】:Automatically built regex expressions that fit set of strings自动构建适合字符串集的正则表达式
【发布时间】:2011-10-06 11:18:39
【问题描述】:

我们已经编写了系统来分析来自大型网络的日志消息。系统从许多不同的网络元素中获取日志消息,并通过正则表达式对其进行分析。例如用户可能写了两条规则:

^cron/script\.sh.*
.*script\.sh [0-9]+$

在这种情况下,只会选择与给定模式匹配的日志。过滤的原因是日志消息可能真的很多,每天最多 1 GB。

现在是我问题的主要部分。由于有很多网络元素,并且它们有几种类型,并且它们中的每一个在路径中都有不同的参数......有没有办法自动生成一组正则表达式,以某种方式对日志进行分组?该系统可以学习历史数据,例如从上周开始。生成的正则表达式一定不是很准确,应该是提示用户将这样的新规则添加到系统中。

我正在考虑使用无监督机器学习将输入分组,然后在每个组中找到合适的正则表达式。有没有其他方法,也许更快或更好?最后但同样重要的是,如何找到匹配所获得组中所有字符串的正则表达式? (重要的是,.* 不是答案。)


编辑经过一番思考,我将尝试简化问题。假设我已经对日志进行了分组。我想(最多)找到三个最大的子字符串(至少一个),这些子字符串对集合中的所有字符串都是通用的。例如:

Set of strings:
cron/script1.sh -abc 1243 all
cron/script2.sh 1
bin/script1.sh -asdf 15

Obtained groups:
/script
.sh 

现在我可以通过将这些组与.*? 连接起来来构建一些简单的正则表达式。在此示例中,它将是 .*?(/script).*?(\.sh ).*?。这似乎是更简单的解决方案。

【问题讨论】:

  • 棘手的问题。考虑到由一位领先的正则表达式专家为此目的编写的工具仍然需要大量用户交互,这可能非常重要:参见regexmagic.com
  • 有一个简单的证明,对于任何有限的字符串集,都有无限数量的正则表达式可以匹配它们,所以是的,它是不平凡的任务。跨度>
  • 我相信可能有一些启发式方法可以找到正则表达式。它不必是完整的正则表达式;我认为只需找到一组常见的子字符串,然后将它们与.*? 连接起来就足够了。
  • 这个问题没有很好的定义。匹配词 w1、w2、...、wN 限制性最强的正则表达式是 w1 + w2 + ... + wN,限制性最小的是 E*。你想要一个在中间?任君挑选。

标签: regex string algorithm


【解决方案1】:

你可以试试这个网站上的工具:http://regex.inginf.units.it/

此工具会自动从一组示例生成正则表达式,因此它应该非常适合您的用例。 在网站上还详细描述了它是如何工作的(它基于基因编程)。

【讨论】:

    【解决方案2】:

    好的,我们将尝试将其分解为可管理的步骤。

      1. For each substring w in s1, in order of non-increasing length,
      2.  assume w is a substring of the other sM
      3.  for each string of the other sN,
      4.   if w is not a substring of sN, disprove assumption and break
      5.  if the assumption held, save w
      6.  if you've found three w that work, break
      7. You have recorded between 0 and 3 w that work.
    

    请注意,并非所有字符串集都保证具有公共子字符串(空字符串除外)。在最坏的情况下,假设 s1 是最长的字符串。 s1 (|s1| = n) 有 O(n^2) 个子串,并且需要 O(n) 来比较 m 个其他字符串中的每一个......所以我相信渐近复杂度是 O(n^2 * nm)...尽管算法很幼稚,但这应该很容易管理(毕竟是多项式,而且是二次的)。

    转换为例如C 代码应该是直截了当的……使用一个带有递减长度循环的滑动窗口来获取 s1 的子字符串,然后使用线性搜索器在其他字符串中查找匹配项。

    我确信有更聪明/渐近更好的方法可以做到这一点,但任何算法都必须查看所有字符串中的所有字符,所以 O(nm)... 可能不完全正确。

    【讨论】:

      【解决方案3】:

      天真地,您可以通过使用 or 连接所有字符串(用管道表示,|)来为给定的一组字符串构造一个正则表达式模式。如果您想要更短的模式更优化,您可以从字符串集中创建一个 trie,然后构造一个正则表达式。例如看看trieregex。

      【讨论】:

        【解决方案4】:

        在我看来,您试图做一些正则表达式没有做的事情。正则表达式从其输入中识别 tokens,仅此而已。由程序的其余部分决定输入来自何处、如何分组以及如何处理它获得的令牌。

        所以,让我们从头开始。您有一个输入流,其中包含来自各种不同网络位置的日志事件。抽象这一点,我们得到一个单一的文本流。有关如何使用 python 以简化方式执行此操作的示例,请参阅this website。

        现在我们有了文本,我们想把它分成逻辑组。这就是您的正则表达式的用途,尽管我们确实应该使用成熟的词法分析器。这些标记转到代码的解析器部分。

        解析器决定用我们收集的令牌做什么。现在是我们分析它们的时候,首先做一些简单的事情。例如,将每个唯一的“名称”标记添加到列表中,并计算出现次数。如果这个数字大于 50,我们输出令牌。

        我在这里掩盖了坚韧不拔的细节。首先,您必须确定标记化的“语言”。例如,如果您有这样的日志字符串:ipOfComputer /full/path/to/script.sh args,那么您的标记化将需要了解这些位。

        阅读本书Lex and yacc 以获得对所涉及的各种主题的出色介绍。请注意,这将独立于您的用户正则表达式位。这也将发生在整个流上,做它的事情。这个程序的输出将变成简单的正则表达式添加到配置文件中。

        【讨论】:

          猜你喜欢
          • 2021-12-10
          • 2021-07-19
          • 2019-07-11
          • 1970-01-01
          • 1970-01-01
          • 2021-11-03
          • 1970-01-01
          • 2010-10-11
          • 1970-01-01
          相关资源
          最近更新 更多