Regex (ECMAScript 2018 или .NET), 140 126 118 100 98 82 байта
^(?!(^.*)(.+)(.*$)(?<!^\2|^\1(?=(|(<?(|(?!\8).)*(\8|\3$){1}){2})*$).*(.)+\3$)!?=*)
Это намного медленнее, чем 98-байтовая версия, потому что ^\1слева от просмотра и, следовательно, оценивается после него. Смотрите ниже простое переключение, которое восстанавливает скорость. Но из-за этого два приведенных ниже TIO ограничены выполнением меньшего набора тестов, чем раньше, и .NET один слишком медленно проверяет свое регулярное выражение.
Попробуйте онлайн! (ECMAScript 2018)
Попробуйте онлайн! (.СЕТЬ)
Чтобы отбросить 18 байт (118 → 100), я бесстыдно украл действительно хорошую оптимизацию из регулярного выражения Нейла, которая избавляет от необходимости помещать заглядывание внутрь отрицательного заднего обзора (в результате получается 80-байтовое неограниченное регулярное выражение). Спасибо тебе, Нил!
Это устарело, когда было отброшено еще 16 невероятных байтов (98 → 82) благодаря идеям jaytea , которые привели к 69-байтовому неограниченному регулярному выражению! Это намного медленнее, но это гольф!
Обратите внимание, что (|(отсутствие операций для обеспечения регулярного связывания регулярного выражения приводит к очень медленной оценке его в .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.