如何将有限模式扩展为所有可能的匹配?

时间:2009-08-08 10:27:35

标签: regex

例如,给定模式

[a-zA-Z]_[0-9]{2}

函数将获取模式并返回包含

的数组或列表
a_00, a_01, a_02, ... , a_98, a_99, ... , z_98, z_99

只需扩展数字和字母(及其有限分组)。我该怎么做呢? Python或Perl中的示例将是首选。谢谢!

3 个答案:

答案 0 :(得分:12)

首先,解析表达式并构建一个反映正则表达式的语法结构的树,并包括一个逻辑上出现在末尾的终结符节点。例如,在lisp表示法中,您的示例可能如下所示:

(concat
  (repeat 2
    (concat
      (charset
        (range a z)
        (range A Z))
      (literal _)
      (charset
        (range 0 9))))
  terminator)

接下来,对树进行线程化,以便您可以使用递归来生成组合扩展。那个,我的意思是,例如a..z中的节点(concat a .. z)都需要指向一个节点,因此a指向b,依此类推,concat节点本身指向它的继任者。我们的想法是你可以在扩展中生成当前元素的一个版本,然后递归到下一个元素,当下一个元素返回时,你可以尝试当前元素的下一个版本等,直到所有版本都用完为止,你回到你的来电者(前任或父母)。使用堆栈和树的后序遍历最简单地完成此线程。如果在后序遍历期间小心地推送节点,则堆栈的顶部将是序列中的下一个元素。

(线程的替代方法是构造树,以便每个concat节点中的下一个元素是前一个节点的子节点,repeat个节点的子节点指向重复节点。 )

然后编写例程(或使用模式匹配的例程集,或者如果树中的节点是使用面向对象语言中的多态实现的,则为虚拟方法),对于任何给定的节点类型,它会生成正确的输出并递归到以适当的方式下一个节点或子节点。例如,在伪代码中:

if node is of form (repeat n): # non-variable repeat
    for i in 1 to n
        recurse into child
    recurse into threaded successor

if node is of form (concat ...):
    recurse into first element # last element will recurse into successor

if node is of form (literal x):
    emit x
    recurse into successor
    remove x

if node is of form (charset ...):
    for each element in charset:
        emit element
        recurse into successor
        remove element

if node is terminator:
    add string created thus far to final output list

等。正如您所看到的,重复节点的子节点不能递归到repeat节点的后继节点,因此在线程化树时需要考虑这一点。当到达repeat节点的子节点的末尾时,需要注意“当前进度”不会丢失;或者,子节点的后继者可以指向重复节点本身(即节点图上的真正闭包),但这需要在某处存储计数器。

总而言之,完成此操作可能需要几天时间,具体取决于它需要的灵活性和高效性。还要注意某些构造,例如Kleene星形或闭包(扩展正则表达式中的*+)将导致无限列表。支持生成器(例如C#的迭代器语法)或协程/连续(例如,Scheme的调用/ cc)或延迟评估(例如Haskell)的语言可以允许迭代列表的前几个元素,而不必评估整个列表。或者,选择随机潜在输出而不是穷举迭代对于提供对应于正则表达式的示例可能是优选的。

答案 1 :(得分:0)

使用thrax !! Thrax提供命令行工具来与重型OpenFST工具包进行交互。您可以在aptmacports等包管理器上找到它。

以下是如何使用thrax对正则表达式进行采样的示例。今天我想弄清楚我正在写的图书馆的名字。我希望这个名字是complete embedded? mrf? (optimization|inference) toolkit的首字母缩写。在尝试手动提出一个名字之后,我放弃并为可能的首字母缩略词编写了以下正则表达式:co?m?e?m?[io]to?

所以现在问题减少了对一些满足这个首字母缩略词的字符串的采样。这就是thrax的用武之地。我们可以先在这样的grm文件中编写正则表达式。

[Save following in file named tmp.grm]
sigma=("c"|"o"|"m"|"e"|"i"|"o"|"t");
export a= Optimize[ ("c":"c") (("o":"")|("o":"o")) (("m":"")|("m":"m")) (("e":"")|("e":"e")) (("m":"")|("m":"m")) (("o":"o")|("i":"i")) ("t":"t") (("o":"")|("o":"o")) ];

你可能猜到发生了什么。对于每个x?,我已指定将输出x或输出''。现在我们可以编译这个grm文件并从语言中采样字符串。

thraxcompiler --save_symbols --input_grammar=tmp.grm --output_far=tmp.far
thraxrandom-generator --far=tmp.far --rule=a --noutput=100

输出包含正则表达式可以匹配的可能字符串。我认为还有一些实用工具可以使用thrax生成所有可能的输出,但是如果你只是采样大量的字符串而uniq它们应该是一个很好的90% solution

****************************************
comemoto
cmemot
****************************************
comemoto
comoto
****************************************
comemoto
comot
****************************************
comemito
coemito
****************************************
comemoto
coeot
****************************************
comemoto
cmeot
****************************************
comemito
coit
****************************************
comemoto
cemot
****************************************
comemoto
ceoto

答案 2 :(得分:-1)

鉴于您可以计算出匹配长度的字符串的长度,您可以通过生成具有正确长度的所有可能字符串来强制它,然后尝试匹配。