Regex (ECMAScript 2018 або .NET), 140 126 118 100 98 82 байт
^(?!(^.*)(.+)(.*$)(?<!^\2|^\1(?=(|(<?(|(?!\8).)*(\8|\3$){1}){2})*$).*(.)+\3$)!?=*)
Це набагато повільніше, ніж версія 98 байтів, тому що ^\1
ліворуч від області пошуку і, таким чином, оцінюється після неї. Дивіться нижче простий комутатор, який відновлює швидкість. Але завдяки цьому два TIO нижче обмежуються виконанням меншого набору тестових випадків, ніж раніше, і .NET один занадто повільний, щоб перевірити власний вираз.
Спробуйте в Інтернеті! (ECMAScript 2018)
Спробуйте в Інтернеті! (.NET)
Щоб скинути 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)
)
)
Я написав це, використовуючи молекулярний lookahead ( 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
.