这是我上一个问题的后续内容。
假设我想生成与给定(简化)正则表达式匹配的所有字符串。
这只是一个编码练习,我没有任何额外的要求(例如,实际生成了多少字符串)。因此,主要需求是生成漂亮、干净、简单的代码。
我曾想过使用Stream
,但看完这个问题后,我想到了Iterator
。你会用什么?
这个问题的解决方案需要太多的代码,所以在这里回答起来很实用,但大纲如下。
首先,您想要解析正则表达式——例如,您可以为此查看解析器组合子。然后你会有一个评估树,看起来像
List(
Constant("abc"),
ZeroOrOne(Constant("d")),
Constant("efg"),
OneOf(Constant("h"),List(Constant("ij"),ZeroOrOne(Constant("klmnop")))),
Constant("qrs"),
AnyChar()
)
您可以将此表达式树作为生成器运行,而不是将其作为matcher来运行,方法是为每个项定义一个generate方法。对于某些术语(例如ZeroOrOne(Constant("d"))
),将有多个选项,因此您可以定义迭代器。一种方法是在每个术语中存储内部状态,并传递"前进"标志或"重置"标志。在"重置"时,生成器返回第一个可能的匹配(例如""
);在前进时,它前进到下一个并返回该值(例如"d"
),同时消耗前进标志(剩下的要在没有标志的情况下进行评估)。如果没有更多的项目,它会对自身内部的所有内容进行重置,并为下一个项目保留前进标志。你从重置开始跑步;在每一次迭代中,你都会提前一步,当你再次得到它时,就会停止。
当然,像"d+"
这样的一些正则表达式结构可以产生无限多的值,所以你可能想以某种方式限制它们(或者在某个时候返回,例如d...d
,意思是"很多");和其他的有很多可能的值(例如.
匹配任何字符,但你真的想要所有64k字符吗,或者有多少unicode代码点?),你可能也希望限制这些值。
无论如何,这虽然很耗时,但会导致发电机工作。顺便说一句,如果您为解析的树的每一部分编写一个匹配例程,那么您还将拥有一个可工作的正则表达式匹配器。