ECMAScript रेजेक्स , 733+ 690+ 158 119 118 ( 117 by) बाइट्स
रेगेक्स में मेरी दिलचस्पी 4 of वर्षों की निष्क्रियता के बाद नए जोश के साथ उभरी है। इस तरह, मैं और अधिक प्राकृतिक संख्या सेट और कार्यों की तलाश में गया, जो कि एक समान ECMAScript रीजेक्स के साथ मेल खाते थे, अपने रेगेक्स इंजन को सुधारना शुरू किया और PCRE पर भी ब्रश करना शुरू कर दिया।
मैं ECMAScript रेगेक्स में गणितीय कार्यों के निर्माण की पराधीनता पर मोहित हूं। समस्याओं को एक पूरी तरह से अलग दृष्टिकोण से संपर्क किया जाना चाहिए, और एक प्रमुख अंतर्दृष्टि के आगमन तक, यह अज्ञात है कि क्या वे बिल्कुल हल करने योग्य हैं। यह खोजने में बहुत व्यापक जाल डालने पर मजबूर करता है कि कौन से गणितीय गुणों का उपयोग किसी विशेष समस्या को हल करने के लिए किया जा सकता है।
तथ्यात्मक संख्याओं का मिलान एक ऐसी समस्या थी जिसे मैंने 2014 में निपटाया भी नहीं था - या अगर मैंने किया, तो केवल क्षण भर में, इसे खारिज कर देना संभव नहीं होने की संभावना है। लेकिन पिछले महीने, मुझे एहसास हुआ कि यह किया जा सकता है।
अपने अन्य ECMA regex पोस्ट के साथ, मैं एक चेतावनी देता हूँ : मैं अत्यधिक सीखने की सलाह देता हूं कि ECMAScript regex में अनैतिक गणितीय समस्याओं को कैसे हल किया जाए। यह मेरे लिए एक आकर्षक यात्रा रही है, और मैं इसे किसी ऐसे व्यक्ति के लिए खराब नहीं करना चाहता, जो संभवतः इसे स्वयं प्रयास करना चाहते हैं, विशेष रूप से संख्या सिद्धांत में रुचि रखने वाले। एक के बाद एक हल करने के लिए लगातार बिगाड़ने-टैग की गई अनुशंसित समस्याओं की सूची के लिए यह पहले वाला पोस्ट देखें ।
तो आगे पढ़िए नहीं अगर आप नहीं चाहते कि आपके लिए कुछ उन्नत यूरीज़ रेगेक्स मैजिक खराब हो जाए । यदि आप स्वयं इस जादू का पता लगाने के लिए एक शॉट लेना चाहते हैं, तो मैं उच्च स्तर पर उल्लिखित उस पोस्ट में उल्लिखित ECMAScript regex में कुछ समस्याओं को हल करके शुरू करने की सलाह देता हूं।
यह मेरा विचार था:
इस संख्या के मिलान के साथ समस्या, अन्य लोगों की तरह, ईसीएमए में यह है कि आमतौर पर दो बदलते नंबरों को लूप में रखना संभव नहीं होता है। कभी-कभी उन्हें बहुसंकेतित किया जा सकता है (उदाहरण के लिए एक ही आधार की शक्तियों को एक साथ अस्पष्ट रूप से जोड़ा जा सकता है), लेकिन यह उनके गुणों पर निर्भर करता है। इसलिए मैं सिर्फ इनपुट नंबर से शुरू नहीं कर सकता था, और 1 तक पहुंचने तक (या तो मैंने सोचा था, कम से कम) तक इसे बढ़ाकर लाभांश से विभाजित कर सकता हूं।
तब मैंने गुटीय संख्याओं में प्रमुख कारकों की बहुलता पर कुछ शोध किया, और सीखा कि इसके लिए एक सूत्र है - और यह एक ऐसा है जिसे मैं शायद ECMA regex में लागू कर सकता हूं!
थोड़ी देर के लिए उस पर स्टू करने के बाद, और इस बीच कुछ अन्य रीजैक्स का निर्माण करने के बाद, मैंने फैक्टरियल रेगेक्स लिखने का काम अपने हाथ में ले लिया। इसमें कई घंटे लगे, लेकिन अच्छी तरह से काम करना समाप्त हो गया। एक अतिरिक्त बोनस के रूप में, एल्गोरिथ्म एक मैच के रूप में व्युत्क्रम गुट को वापस कर सकता है। इससे कोई परहेज नहीं था, यहां तक कि; ECMA में इसे कैसे लागू किया जाना चाहिए, इसकी प्रकृति से, यह अनुमान लगाने के लिए आवश्यक है कि उलटा फैक्टरियल कुछ और होने से पहले क्या है।
नकारात्मक पक्ष यह था कि यह एल्गोरिथ्म एक बहुत लंबे रेगेक्स के लिए बनाया गया था ... लेकिन मुझे खुशी थी कि यह मेरे 651 बाइट गुणन रेगेक्स (एक है कि समाप्त हो गया है अप्रचलित में इस्तेमाल की जाने वाली तकनीक की आवश्यकता है, क्योंकि एक 50 के लिए बनाई गई एक अलग विधि) बाइट रेगेक्स)। मैं एक समस्या की उम्मीद कर रहा था कि इस ट्रिक की आवश्यकता होगी: दो नंबरों पर काम करना, जो एक ही आधार की दोनों शक्तियां हैं, एक लूप में, उन्हें एक साथ जोड़कर और प्रत्येक पुनरावृत्ति पर उन्हें अलग करना।
लेकिन इस एल्गोरिथ्म की कठिनाई और लंबाई के कारण, मैंने (?*...)
इसे लागू करने के लिए आणविक लाहाहिद (रूप का ) का उपयोग किया। यह एक सुविधा है जो ECMAScript या किसी अन्य मुख्यधारा के रेगेक्स इंजन में नहीं है, लेकिन एक जिसे मैंने अपने इंजन में लागू किया था । आणविक लुकहेड के अंदर किसी भी कैप्चर के बिना, यह कार्यात्मक रूप से एक परमाणु लुकहेड के बराबर है, लेकिन कैप्चर के साथ यह बहुत शक्तिशाली हो सकता है। इंजन लुकहैड में वापस आ जाएगा, और इसका उपयोग ऐसे मूल्य को व्यक्त करने के लिए किया जा सकता है जो इनपुट के पात्रों का उपभोग किए बिना सभी संभावनाओं (बाद में परीक्षण के लिए) के माध्यम से चक्र करता है। उनका उपयोग करके एक बहुत क्लीनर कार्यान्वयन के लिए कर सकते हैं। (वैरिएबल-लेंथ लुकहैंड आणविक लुकहेड की शक्ति में बहुत कम से कम बराबर है, लेकिन बाद वाला अधिक सरल और सुरुचिपूर्ण कार्यान्वयन के लिए जाता है।)
तो 733 और 690 बाइट लंबाई वास्तव में समाधान के ECMAScript- संगत अवतार का प्रतिनिधित्व नहीं करते हैं - इसलिए उनके बाद "+"; यह निश्चित रूप से उस एल्गोरिथ्म को शुद्ध ईसीएमएस्क्रिप्ट (जो इसकी लंबाई काफी बढ़ा देगा) को पोर्ट करना संभव है, लेकिन मुझे इसके आसपास नहीं मिला ... क्योंकि मैंने बहुत सरल और अधिक कॉम्पैक्ट एल्गोरिथ्म के बारे में सोचा था! एक है कि आसानी से आणविक लाह के बिना लागू किया जा सकता है। यह काफी तेज भी है।
यह नया, पिछले की तरह, सभी संभावनाओं के माध्यम से साइकलिंग और एक मैच के लिए परीक्षण करके, उलटे फैक्टरियल पर एक अनुमान लगाना चाहिए। यह उस काम के लिए जगह बनाने के लिए N को 2 से विभाजित करता है, और फिर उसे एक लूप सीड करना होता है, जिसमें वह बार-बार एक विभाजक द्वारा इनपुट को विभाजित करेगा जो 3 से शुरू होता है और हर बार वेतन वृद्धि करता है। (जैसे, 1 और 2; मुख्य एल्गोरिथ्म से मेल नहीं खा सकता है, और इसे अलग से निपटाया जाना चाहिए।) भाजक को चालू भाग में जोड़कर ट्रैक रखा जाता है; इन दो नंबरों को स्पष्ट रूप से अलग किया जा सकता है, क्योंकि 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 बाइट द्वारा एक बार फिर से दबाया जा रहा है!
संपादित करें: मैं ग्रिम द्वारा पाए गए एक ट्रिक का उपयोग करके 1 बाइट (119 → 118) छोड़ने में सक्षम था जो कि इस मामले में विभाजन को छोटा कर सकता है कि भागफल से अधिक या बराबर होने की गारंटी है।
आगे कोई हलचल नहीं है, यहाँ regex है:
सही / गलत संस्करण (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
इन रेगेक्स के मेरे गोल्फ अनुकूलन का पूरा इतिहास गितुब पर है:
फैक्टरियल नंबरों के मिलान के लिए रेगेक्स - गुणन-तुलना पद्धति, आणविक लुकहैड के साथ।
रेगेक्स से संबंधित फैक्टरियल नंबरों के लिए रेगेक्स। टीएक्स (ऊपर दिखाया गया है)
((x*)x*)
((x*)+)
((x+)+)
n = 3 !\2
3 - 3 = 0
.NET regex इंजन अपने ECMAScript मोड में इस व्यवहार का अनुकरण नहीं करता है, और इस प्रकार 117 बाइट regex काम करता है:
इसे ऑनलाइन आज़माएं! (घातीय-मंदी संस्करण, .NET रेगेक्स इंजन + ECMAScript उत्सर्जन के साथ)
1
?