Regex (ECMAScript 2018 lub .NET), 140 126 118 100 98 82 bajtów
^(?!(^.*)(.+)(.*$)(?<!^\2|^\1(?=(|(<?(|(?!\8).)*(\8|\3$){1}){2})*$).*(.)+\3$)!?=*)
Jest to znacznie wolniejsze niż wersja 98-bajtowa, ponieważ ^\1lewa strona z wyprzedzeniem, a zatem jest oceniana po niej. Poniżej znajduje się prosty przełącznik, który odzyskuje prędkość. Ale z tego powodu dwa poniższe TIO są ograniczone do ukończenia mniejszego zestawu przypadków testowych niż wcześniej, a jeden .NET jest zbyt wolny, aby sprawdzić swój regex.
Wypróbuj online! (ECMAScript 2018)
Wypróbuj online! (.NETTO)
Aby upuścić 18 bajtów (118 → 100), bezwstydnie ukradłem naprawdę fajną optymalizację z wyrażenia regularnego Neila, który pozwala uniknąć konieczności umieszczania spojrzenia w środku negatywnego spojrzenia (uzyskując 80 bajtów nieograniczonego wyrażenia regularnego). Dziękuję Neil!
Stało się to przestarzałe, kiedy zrzuciło niewiarygodne 16 dodatkowych bajtów (98 → 82) dzięki pomysłom jaytea , które doprowadziły do 69-bajtowego nieograniczonego wyrażenia regularnego! Jest znacznie wolniejszy, ale to golf!
Zauważ, że (|(brak operacji poprawienia powiązania wyrażenia regularnego powoduje, że ocenia on bardzo powoli w .NET. Nie mają tego efektu w ECMAScript, ponieważ opcjonalne dopasowania o zerowej szerokości są traktowane jako niepasujące .
ECMAScript zabrania kwantyfikatorów w odniesieniu do asercji, co utrudnia grę w golfa w ograniczonych źródłach . Jednak w tym momencie gra jest tak dobrze golfa, że nie sądzę, aby zniesienie tego konkretnego ograniczenia otworzyło dalsze możliwości gry w golfa.
Bez dodatkowych znaków potrzebnych do przejścia przez ograniczenia ( 101 69 bajtów):
^(?!(.*)(.+)(.*$)(?<!^\2|^\1(?=((((?!\8).)*(\8|\3$)){2})*$).*(.)+\3))
Jest powolny, ale ta prosta edycja (tylko 2 dodatkowe bajty) odzyskuje utraconą prędkość i więcej:
^(?!(.*)(.+)(.*$)(?<!^\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)
)
)
Napisałem go za pomocą molekularnego lookahead ( 103 69 bajtów) przed przekształceniem go w look-look o zmiennej długości:
^(?!.*(?*(.+)(.*$))(?!^\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}
)*$
)
)
Aby pomóc w poprawnym powiązaniu mojego wyrażenia regularnego, użyłem odmiany powyższego wyrażenia regularnego:
(?*(.+)(.*$))(?!^\1$|(?*(.)+.*\2$)((((?!\3).)*(\3|\2$)){2})*$)\1
W połączeniu z regex -xml,rs -otym identyfikuje ścisły podciąg wejściowy, który zawiera parzystą liczbę każdego znaku (jeśli taki istnieje). Jasne, mógłbym napisać program, który nie robi wyrażeń regularnych, aby to dla mnie zrobić, ale gdzie byłaby w tym zabawa?
abcbca -> False.