字符串
p
的句点w
是任意正整数p
,w[i]=w[i+p]
每当定义这个等式的两边时。让per(w)
表示 最小句点w
的大小。我们说字符串w
是 周期性iffper(w) <= |w|/2
。
非正式地,周期性字符串只是一个由重复至少两次的前缀组成的字符串。唯一的复杂因素是,在字符串的末尾,我们不需要前缀的完整副本。
例如,考虑字符串x = abcab
。 per(abcab) = 3
为x[1] = x[1+3] = a
,x[2]=x[2+3] = b
并且没有较小的期限。因此字符串abcab
不是周期性的。但是,字符串ababa
定期为per(ababa) = 2
。
作为更多示例,abcabca
,ababababa
和abcabcabc
也是定期的。
是否有正则表达式来确定字符串是否是周期性的?
我真的不介意正则表达式的哪种风格,但如果它有所作为,那么Python re
支持的任何内容。
答案 0 :(得分:5)
您需要的是反向引用
\b(\w*)(\w+\1)\2+\b
这甚至与abcabca
和ababababa
匹配。
请注意,作为反向引用的机制(在这种情况下是必要的)使表达式属于非常规语法。
答案 1 :(得分:4)
您可以使用Regex反向引用。
例如(.+)\1+
。此模式将匹配由至少一个字符()
组成的组.+
。该组\1
(后退参考)必须至少重复一次才能进行比赛。
字符串ababa
匹配,并找到ab
作为第一组。
字符串abcab
不匹配。
稍后修改
如果您想要重复至少两次的前缀,可以将模式更改为:^(.+)\1+
。问题是我认为你不能将字符串的结尾与前缀的子字符串匹配。因此,任何以重复模式开头的字符串都会匹配,但它会忽略字符串的结尾。
以后编辑
受到@tobias_k回答的启发,我就是这样做的^((.+)(?:.*))\1+\2?$
。它查找具有前缀的字符串(它查找它可以找到的最长前缀),该字符串重复至少两次,结尾必须是前缀的起始部分。
匹配中的第一个捕获组将是重复的前缀。
https://regex101.com/r/jQ3yY1/2
如果您想要重复的最短前缀,可以使用此模式^((.+?)(?:.*?))\1+\2?$
。
答案 2 :(得分:4)
您可以使用^(.+)(.*)(\1\2)+\1?$
等正则表达式。
^...$
从字符串的开头到结尾(.+)
一段时间内始终重复(例如a
中的ababa
)(.*)
句号的可选部分,在结尾处重复(例如b
中的ababa
)(\1\2)+
整个时期的一次或多次重复\1?
期间第一部分的可选最终重复在Python中:
>>> p = r"^(.+)(.*)(\1\2)+\1?$"
>>> re.match(p, "abcab")
None
>>> re.match(p, "abcabca")
<_sre.SRE_Match at 0x7f5fde6e51f8>
请注意,这与空字符串""
不匹配,但也可以认为是周期性的。如果应匹配空字符串,则必须单独处理,例如只需在正则表达式的末尾附加|^$
即可。