正则表达式(ECMAScript的2018或.NET),140 126 118 100 98 82个字节
^(?!(^.*)(.+)(.*$)(?<!^\2|^\1(?=(|(<?(|(?!\8).)*(\8|\3$){1}){2})*$).*(.)+\3$)!?=*)
这比98字节的版本要慢得多,因为^\1
前瞻的左侧是,因此在之后进行评估。请参阅以下有关重新获得速度的简单switcheroo。但是由于这个原因,下面的两个TIO只能完成比以前更小的测试用例集,.NET太慢了,无法检查自己的正则表达式。
在线尝试!(ECMAScript 2018)
在线尝试!(。净)
要删除18个字节(118→100),我无耻地从Neil的正则表达式中窃取了一个非常不错的优化,它避免了在负向后的内部留一个先行(产生80字节的不受限制的正则表达式)。谢谢,尼尔!
由于jaytea的想法导致了69字节无限制的正则表达式,它又掉了16个字节(98→82),这变得过时了!它慢得多,但这就是高尔夫!
请注意,(|(
使正则表达式良好链接的无操作的结果是使它在.NET下的评估非常缓慢。它们在ECMAScript中没有此效果,因为零宽度的可选匹配被视为非匹配。
ECMAScript禁止在断言上使用量词,因此这使限制源要求打高尔夫变得更加困难。但是,在这一点上,它是如此出色,以至于我认为取消这一特定限制不会为高尔夫运动带来更多可能性。
没有通过限制的额外字符(101 69字节):
^(?!(.*)(.+)(.*$)(?<!^\2|^\1(?=((((?!\8).)*(\8|\3$)){2})*$).*(.)+\3))
速度很慢,但是这个简单的编辑(仅增加2个字节)重新获得了所有丢失的速度,甚至更多:
^(?!(.*)(.+)(.*$)(?<!^\2|(?=\1((((?!\8).)*(\8|\3$)){2})*$)^\1.*(.)+\3))
^
(?!
(.*) # cycle through all starting points of substrings;
# \1 = part to exclude from the start
(.+) # cycle through all ending points of non-empty substrings;
# \2 = the substring
(.*$) # \3 = part to exclude from the end
(?<! # Assert that every character in the substring appears a total
# even number of times.
^\2 # Assert that our substring is not the whole string. We don't
# need a $ anchor because we were already at the end before
# entering this lookbehind.
| # Note that the following steps are evaluated right to left,
# so please read them from bottom to top.
^\1 # Do not look further left than the start of our substring.
(?=
# Assert that the number of times the character \8 appears in our
# substring is odd.
(
(
((?!\8).)*
(\8|\3$) # This is the best part. Until the very last iteration
# of the loop outside the {2} loop, this alternation
# can only match \8, and once it reaches the end of the
# substring, it can match \3$ only once. This guarantees
# that it will match \8 an odd number of times, in matched
# pairs until finding one more at the end of the substring,
# which is paired with the \3$ instead of another \8.
){2}
)*$
)
.*(.)+ # \8 = cycle through all characters in this substring
# Assert (within this context) that at least one character appears an odd
# number of times within our substring. (Outside this negative lookbehind,
# that is equivalent to asserting that no character appears an odd number
# of times in our substring.)
\3 # Skip to our substring (do not look further right than its end)
)
)
我使用分子先行(103 69字节)编写了该代码,然后将其转换为可变长度先行代码:
^(?!.*(?*(.+)(.*$))(?!^\1$|(?*(.)+.*\2$)((((?!\3).)*(\3|\2$)){2})*$))
^
(?!
.*(?*(.+)(.*$)) # cycle through all non-empty substrings;
# \1 = the current substring;
# \2 = the part to exclude from the end
(?! # Assert that no character in the substring appears a
# total even number of times.
^\1$ # Assert that our substring is not the whole string
# (i.e. it's a strict substring)
|
(?*(.)+.*\2$) # \3 = Cycle through all characters that appear in this
# substring.
# Assert (within this context) that this character appears an odd number
# of times within our substring.
(
(
((?!\3).)*
(\3|\2$)
){2}
)*$
)
)
为了帮助我的正则表达式本身建立良好的链接,我一直在使用上述正则表达式的变体:
(?*(.+)(.*$))(?!^\1$|(?*(.)+.*\2$)((((?!\3).)*(\3|\2$)){2})*$)\1
与一起使用时regex -xml,rs -o
,它将标识输入的严格子字符串,其中包含偶数个每个字符(如果存在)。当然,我可以编写一个非正则表达式程序来为我执行此操作,但是这样做的乐趣何在?
abcbca -> False
。