正则表达式为9的倍数


14

描述一个可以识别9的倍数的有限状态机很容易:跟踪数字总和(mod 9)并添加下一个接受的数字。这样的FSM只有9个状态,非常简单!通过FSM可识别性和常规语言之间的等效性,存在一个9的倍数的正则表达式。但是,任何此类正则表达式都可能……非常……长。与之类似,可能约为千兆字节。

https://www.quaxio.com/triple/上有一个有效的示例,可用于3的倍数。在页面底部,作者提供了一种“手动优化”的解决方案,该解决方案比原始转换要短一些。 FSM到正则表达式。

挑战:

您必须制作一个正则表达式来检测9的倍数。由于这种正则表达式预计会很长,因此我要求您提供一个可以打印正则表达式的程序。(如果您真的想提供一个完整的正则表达式,也许将其放在其他位置并在此处链接!)

您必须能够告诉我们您程序输出的准确字符数-因此,只有在程序运行得足够快的情况下,才可以尝试尝试一定长度的所有正则表达式,直到找到有效的正则表达式,这是不可接受的运行它完成并给我们最终的正则表达式长度!

当然,点是用于具有最短的输出正则表达式,而不是基于程序长度。由于正则表达式是我要的“程序”,并且在这里方便地传输太长了,因此我仍在标记此代码高尔夫球。

规则:

  • 输入将仅包含匹配的字符[0-9]*
  • 您的正则表达式应匹配 9的倍数,但不能匹配其他任何东西。并非完全由数字0-9组成且为无效输入的案例可以根据需要匹配或失败。
  • 考虑到DFA易于识别的动机,所得的正则表达式实际上必须是更具理论性的术语中的正则表达式,也就是说,仅是封闭正则语言的运算符。确切地说,唯一允许的事情是:
    • 文字,字符范围([ab][a-f][^k]),Kleene星(*),锚(^$),通过括号分组,在交替(|),可选术语(?),一个或更多的术语(+),向前看符号((?=)),负向前看符号((?!)), lookbehinds( (?<=)),负lookbehinds( (?<!)),条件(如在https://www.regular-expressions.info/conditional.html - (?(?=test)then|else)),和有界长度的反向引用(见下文)。
  • 那些东西例子不是不允许的:
    • 任意长度的后向引用,前向引用,递归,子例程,循环结构,可执行代码,任何'eval'变体或用于将字符串转换为算术值的内置结构。
  • 可以显示具有有限长度绑定字符串的反向引用是可以接受的,因为它们可以以有限状态存储并且不会改变语言的规则性。例如,正则表达式(..2.[3-5])4\1.\1是可以接受的,因为捕获组上有绑定长度\1。这是常规建筑。之类的构造(2*)0\1是不可接受的,因为捕获的组无法以有限状态存储。
  • 您的正则表达式可以随意接受或拒绝带有多余前导零的整数。但是,"0"必须接受该字符串。

2
相关的,不确定是否将其视为重复项
ASCII纯字符,

啊,嗯!我搜索了“正则表达式多个”,但没有“正则表达式可整”。我想那是非常相似的,是的。
亚历克斯·梅伯格

11
还没有人说,所以欢迎来到PPCG和有趣的第一个挑战!正如另一位用户所提到的那样,通常建议(但不是必需)在沙箱中发布挑战建议,以便他们可以在发布到主项目之前获得反馈。但是,这是一个经过深思熟虑的明确挑战,因此没有理由将其移至沙盒中。希望您喜欢我们的社区!
Caird coinheringaahing

小于200 kb的解决方案是可能的,因此它不会那么庞大
Ton Hospel

3
使用.NET扩展名的解决方案:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
Neil

Answers:


3

Haskell207,535 202,073字节

使用0|9而不是[09]在可能的地方保存5,462字节。

digits n
  | x == 0    = "0|9"
  | otherwise = show x
  where x = mod n 9

regex 0 = "[09]*"
regex n = (regex' n (-1) (-1)) ++ "*"

regex' 0 start end = digits (end - start)
regex' n start end = '(':(regex' 0 start end) ++ (concat ['|':(regex' (n-x) (start-x) (-1)) ++ (regex (n-x))
                                                  ++ (regex' (n-x) (-1) (end-x)) | x <- [1..n]]) ++ ")"

main = do
  putStr ("^" ++ (regex 8) ++ "$")

在线尝试!

只是快速修改了链接文章脚注中给出的正则表达式即可开始工作。

输出正则表达式的Pastebin,由Herman Lauenstein提供。

虽然我无法测试完整的正则表达式,但修改程序以将可除数检查3却得到与我基于此的正则表达式完全相同的东西。此外,修改程序以将数字总和的除数检查4或5似乎也适用于我测试过的数字。


您还可以测试您的方法对2除数(应类似于/even$/)和对5除数(应类似于/[05]$/)的含义。PS:提及代码的语言
Ton Hospel,

是带有输出的pastebin(所有出现的内容都([09]|替换为(0|9|以节省数千个字节)
Herman L
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.