Regex Golf通关记录(4)——数字篇上

Regex Golf网址:https://alf.nu/RegexGolf

Regex Golf通关解答:Regex Golf通关解答-优快云博客

Regex Golf上有几道题目是跟数字相关的——让我们去匹配某些特定数字长度的字符串,或者有某种特点的数字。而这些用法,在我接触Regex Golf之前是完全想不到的。我隐约感觉,除了能帮我们提高自身正则表达式的技术之外,或许Regex Golf它本身也在探讨正则表达式的极限。

Prime –

Prime题目本身已经说明了本题的意图,即让我们去匹配一个长度为质数的字符串。然而我第一次拿到这个题目时的确是一头雾水,本能的感觉这是不可能完成的任务。众所周知,我们无法通过公式去构造一个质数,那又如何能表达出一个质数长度的字符串呢?

所以当我看到别人把“质数”的概念转换为“非合数”,进而解题的时候,我由衷的赞同这个思路的美妙。对啊,我们不需要构造“质数”长度的字符串,只需要构造“合数”长度的字符串,然后利用否定的零宽断言进行取反就好了。而合数长度的字符串构造起来似乎没那么困难,任意一个大于一长度的字符串进行两次以上的重复就好了,于是我写下了第一版的答案:^(?!(..+){2,}$)。

然而这个答案是错误的。其原因在于,{2,} 这样的方法是对前面模式的重复,而不是对前面捕获分组的重复。也就是说(..+){2,}完全可以匹配字符串“xxxxx”,因为它可以按照第一次“xx”,第二次“xxx”的模式去进行匹配。要对捕获的分组进行多次重复,正确的写法是:(..+)\1+,先通过\1对捕获分组进行重复,然后在通过+对\1进行重复。所以本题的答案为:^(?!(..+)\1+$)。

Powers

本题要求匹配长度为2的幂次的字符串。有了上一题的经验,已经没有了那种不可能完成的感觉了。于是我尝试着对长度1,2,4,8……进行构造:x, (x)\1, ((x)\2)\1, (((x)\3)\2)\1……将他们进行了合并,得到了我的第一版答案:^((((((((((.)\10?)\9?)\8?)\7?)\6?)\5?)\4?)\3?)\2?)\1?$,一个只能匹配 2^{0} ~ 2^{10} 长度字符串的正则表达式。

上面的答案显然不够优秀。我们参考Prime一题的思路,2的幂次方意味着没有任何奇数约数,我们只要能够构造出有奇数约数长度的字符串,然后取反就好了。根据这个思路,构造出本题的答案为:^(?!(.(..)+)\1*$)。

Powers 2–Or 3.

这次是匹配3的幂次长度的字符串,根据上一题的经验,我们可以直接构造 3^{0} ~ 3^{10}长度的字符串:^(((((((((x)(\9\9)?)(\8\8)?)(\7\7)?)(\6\6)?)(\5\5)?)(\4\4)?)(\3\3)?)(\2\2)?)(\1\1)?$;或者,对拥有3n+1, 3n+2(2需要做特殊处理)约数长度的字符串取反:^(?!(xx|(xxx)+xx?)\1*$)。

但即使是这种解法,依然使用了23个字符。而就算我只匹配页面用例,再减少两个字符:^(?!(xx|(xxx)+x)\1*$),还是达不到19个字符,也就是说,这道题目还有更优秀的解法!我承认我又一次被震撼了……还是直接来欣赏一下最佳答案吧:^((x+)\2(?=\2$))*x$。

这个正则表达式反复确认剩余子串可以被3整除,并匹配前前三分之二的内容,直至最后剩下一个字符,进行匹配结束。这是递归?!……所以我才会说这些题目是对正则表达式极限的探讨,我从来都没想到过在一个不支持递归语法的正则引擎里居然真的能实现递归的效果。(Powers一题也可以使用这种方式解答:^((x+)(?=\2$))*x$,但所用字符数依然是17个)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值