ECMAScript를 정규식 733+ 690+ 158 119 118 (117🐌) 바이트
정규식에 대한 나의 관심은 4½ 년 동안 활동이 없었던 새로운 활력으로 촉발되었습니다. 따라서 나는 단항 ECMAScript 정규 표현식과 일치하는 더 자연스러운 숫자 세트와 기능을 찾고 정규식 엔진 개선을 재개했으며 PCRE에서도 브러시 작업을 시작했습니다.
ECMAScript 정규식에서 수학 함수를 작성하는 외계인에 매료되었습니다. 완전히 다른 관점에서 문제에 접근해야하며, 핵심 통찰력이 도착할 때까지 문제가 해결 가능한지 여부는 알 수 없습니다. 특정 문제를 해결하기 위해 사용할 수있는 수학적 속성을 찾는 데 훨씬 더 넓은 그물을 캐스트합니다.
계승 수를 일치시키는 것은 2014 년에도 다루지 않았던 문제였습니다. 또는 내가 그럴 가능성이 너무 적다는 것을 잠시 무시한 것입니다. 그러나 지난 달, 나는 그것이 가능하다는 것을 깨달았습니다.
다른 ECMA 정규 표현식 게시물과 마찬가지로 경고 메시지 가 표시됩니다. ECMAScript 정규 표현식에서 단항 수학 문제를 해결하는 방법을 배우는 것이 좋습니다. 그것은 나를 위해 매혹적인 여행이었고, 나는 그것을 스스로 시도하고 싶을지도 모르는 사람, 특히 수 이론에 관심이있는 사람들을 위해 그것을 망치고 싶지 않습니다. 스포일러 태그가 붙은 권장 문제를 하나씩 해결하기위한 연속적인 문제 목록은 이 게시물 을 참조하십시오 .
따라서 고급 단항 정규식 마법을 원하지 않는다면 더 이상 읽지 마십시오 . 이 마법을 스스로 파악하는 데 총력을 기울이고 싶다면 위에 링크 된 게시물에 요약 된 ECMAScript 정규식의 일부 문제를 해결하는 것이 좋습니다.
이것은 내 생각이었다 :
대부분의 다른 것과 마찬가지로이 숫자 집합을 일치시키는 문제는 ECMA에서 일반적으로 루프에서 두 개의 변화하는 숫자를 추적 할 수 없다는 것입니다. 때때로 그것들은 다중화 될 수 있습니다 (예 : 같은베이스의 힘을 모호하게 추가 할 수 있습니다). 그러나 그것은 그들의 속성에 달려 있습니다. 따라서 입력 번호로 시작하여 1에 도달 할 때까지 점진적으로 증가하는 배당으로 나눌 수 없었습니다 (적어도 생각했습니다).
그런 다음 요인 수의 소수 요인에 대한 몇 가지 연구를 수행하고 이에 대한 공식이 있다는 것을 알게 되었습니다. 이는 ECMA 정규식에서 구현할 수있는 것입니다!
잠시 동안 그것을 조롱하고 그 동안 다른 정규 표현식을 작성한 후, 나는 계승 정규 표현식을 작성하는 임무를 맡았습니다. 몇 시간이 걸렸지 만 결국 잘 작동했습니다. 추가 보너스로 알고리즘은 역 계승을 일치로 반환 할 수 있습니다. 심지어 피하는 것도 없었다. ECMA에서 구현되어야하는 방식의 본질 상, 다른 일을하기 전에 역 계승이 무엇인지 추측해야합니다.
단점은이 알고리즘이 매우 긴 정규식을 위해 만들어 졌다는 것입니다 ...하지만 651 바이트 곱셈 정규식 (50에 대한 다른 방법으로 인해 쓸모없는 결과)에 사용되는 기술이 필요하다는 것을 알게되어 기뻤습니다 바이트 정규식). 나는이 트릭을 필요로하는 문제가 발생하기를 바랐다. 동일한베이스의 두 가지 힘인 두 숫자를 반복적으로 반복하여 모아서 추가하고 각 반복에서 분리하여 루프에서
그러나이 알고리즘의 어려움과 길이로 인해 분자 모양을 사용하여 알고리즘 (?*...)
을 구현했습니다. 이는 ECMAScript 또는 다른 주류 정규식 엔진이 아니라 엔진에서 구현 한 기능입니다 . 분자식 미리보기 내부에 캡처가 없으면 기능적으로 원자 적 미리보기와 동일하지만 캡처하면 매우 강력 할 수 있습니다. 엔진은 lookahead로 역 추적되며, 입력 문자를 소비하지 않고 모든 가능성 (나중에 테스트를 위해)을 순환하는 값을 추측하는 데 사용될 수 있습니다. 그것들을 사용하면 훨씬 깔끔한 구현이 가능합니다. (가변 길이 룩 베어는 분자 룩어 헤드와 비교하여 최소한의 힘이지만, 후자는보다 간단하고 우아한 구현을 만드는 경향이 있습니다.)
따라서 733 및 690 바이트 길이는 실제로 솔루션의 ECMAScript 호환 화신을 나타내지 않습니다. 따라서 "+"는 뒤에옵니다. 그 알고리즘을 순수한 ECMAScript (길이가 조금 길어질 것입니다)로 이식하는 것이 가능하지만 훨씬 더 간단하고 컴팩트 한 알고리즘을 생각했기 때문에 그 방법을 찾지 못했습니다! 분자 예견없이 쉽게 구현할 수있는 것. 또한 훨씬 빠릅니다.
이 새로운 것은 이전과 마찬가지로 역 요인을 추측하여 모든 가능성을 순환하고 일치하는지 테스트해야합니다. N을 2로 나눠서 필요한 작업을위한 공간을 마련한 다음 입력을 3으로 시작하고 매번 증가하는 제수로 반복적으로 입력을 나누는 루프를 시드합니다. (따라서 1!과 2!는 주 알고리즘과 일치시킬 수 없으며 별도로 처리해야합니다.) 제수는 실행 몫에 추가하여 추적합니다. 이 두 숫자는 M! == N, 실행 몫은 M과 같아 질 때까지 M으로 계속 나눌 수 있습니다.
이 정규식은 루프의 가장 안쪽 부분에서 변수별로 나눕니다. 나누기 알고리즘은 다른 정규 표현식과 동일하며 곱셈 알고리즘과 유사합니다. A≤B, A * B = C 인 경우 C % A = 0 및 B가 B≤C를 만족하는 가장 큰 숫자 인 경우에만 및 C % B = 0 및 (CB- (A-1)) % (B-1) = 0 (여기서 C는 피제수, A는 제수, B는 몫). (A≥B 인 경우에도 유사한 알고리즘을 사용할 수 있으며, A와 B를 비교하는 방법을 모르는 경우 하나의 추가 분할 성 테스트 만 있으면됩니다.)
그래서 문제가 골프 최적화 피보나치 정규식 보다 훨씬 덜 복잡하게 줄어들 수 있다는 것을 좋아 하지만 멀티플렉싱 파워 오브 더 동일한베이스 기술이 다른 문제를 기다려야한다는 실망에 한숨을 쉬고 있습니다. 이것은 실제로 필요하지 않기 때문에 필요합니다. 내 651 바이트 곱셈 알고리즘이 50 바이트로 대체되고 있다는 이야기입니다.
편집 : 몫이 제수보다 크거나 같은 경우 Grimy 가 발견 한 트릭을 사용하여 1 바이트 (119 → 118)를 삭제할 수있었습니다 .
더 이상 고민하지 말고 정규 표현식을 사용하십시오.
참 / 거짓 버전 (118 바이트) :
^((x*)x*)(?=\1$)(?=(xxx\2)+$)((?=\2\3*(x(?!\3)xx(x*)))\6(?=\5+$)(?=((x*)(?=\5(\8*$))x)\7*$)x\9(?=x\6\3+$))*\2\3$|^xx?$
온라인으로 사용해보십시오!
역 계승 또는 불일치 (124 바이트)를 반환합니다.
^(?=((x*)x*)(?=\1$)(?=(xxx\2)+$)((?=\2\3*(x(?!\3)xx(x*)))\6(?=\5+$)(?=((x*)(?=\5(\8*$))x)\7*$)x\9(?=x\6\3+$))*\2\3$)\3|^xx?$
온라인으로 사용해보십시오!
ECMAScript +\K
(120 바이트) 로 역 계승 또는 불일치를 반환합니다 .
^((x*)x*)(?=\1$)(?=(xxx\2)+$)((?=\2\3*(x(?!\3)xx(x*)))\6(?=\5+$)(?=((x*)(?=\5(\8*$))x)\7*$)x\9(?=x\6\3+$))*\2\K\3$|^xx?$
그리고 코멘트가있는 자유 공간 버전 :
^
(?= # Remove this lookahead and the \3 following it, while
# preserving its contents unchanged, to get a 119 byte
# regex that only returns match / no-match.
((x*)x*)(?=\1$) # Assert that tail is even; \1 = tail / 2;
# \2 = (conjectured N for which tail == N!)-3; tail = \1
(?=(xxx\2)+$) # \3 = \2+3 == N; Assert that tail is divisible by \3
# The loop is seeded: X = \1; I = 3; tail = X + I-3
(
(?=\2\3*(x(?!\3)xx(x*))) # \5 = I; \6 = I-3; Assert that \5 <= \3
\6 # tail = X
(?=\5+$) # Assert that tail is divisible by \5
(?=
( # \7 = tail / \5
(x*) # \8 = \7-1
(?=\5(\8*$)) # \9 = tool for making tail = \5\8
x
)
\7*$
)
x\9 # Prepare the next iteration of the loop: X = \7; I += 1;
# tail = X + I-3
(?=x\6\3+$) # Assert that \7 is divisible by \3
)*
\2\3$
)
\3 # Return N, the inverse factorial, as a match
|
^xx?$ # Match 1 and 2, which the main algorithm can't handle
이 정규식의 내 골프 최적화의 전체 역사는 github에 있습니다.
계승 번호 일치하는 정규식 - 다수 - 비교에있어서, 분자와 lookahead.txt의
계승 numbers.txt 일치위한 정규식 (하나 위에 표시된)
((x*)x*)
((x*)+)
((x+)+)
n = 3 !\2
3 − 3 = 0
.NET 정규식 엔진은 ECMAScript 모드에서이 동작을 에뮬레이트하지 않으므로 117 바이트 정규식이 작동합니다.
온라인으로 사용해보십시오! (.NET 정규식 엔진 + ECMAScript 에뮬레이션을 사용한 지수 감속 버전)
1
?