यह कैसे निर्धारित किया जाए कि कोई संख्या regex के साथ अभाज्य है?


128

मुझे जावा पर निम्नलिखित कोड उदाहरण मिला रोसेट्टाकोड :

public static boolean prime(int n) {
  return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
  • मैं विशेष रूप से जावा को नहीं जानता, लेकिन इस स्निपेट के सभी पहलुओं को समझता हूं, केवल रेगेक्स को छोड़कर
  • मेरे पास रेगेक्स के बुनियादी-उन्नत ज्ञान के लिए बुनियादी है क्योंकि आप इसे अंतर्निहित पीएचपी कार्यों में पाते हैं

.?|(..+?)\\1+अभाज्य संख्याओं का मिलान कैसे होता है ?


9
@ एमीर रचुम: !new String(new char[n]).matches(".?|(..+?)\\1+")के बराबर है !((new String(new char[n])).matches(".?|(..+?)\\1+"))
गुमबो

14
यह न केवल कम्प्यूटेशनल रूप से महंगा है, बल्कि संभावित रूप से विनाशकारी मेमोरी-महंगा भी है। यदि कोई इस दृष्टिकोण का उपयोग करना चुनता है, जिसे मैं एल्गोरिदम के बाद से सलाह दूंगा कि प्राइम्स खोजने के लिए इतना आसान है (दुनिया में इसे जटिल क्यों बनाते हैं और इसे इतना बेकार बना देते हैं), तो एक चेक "नया चार" से पहले आयोजित किया जाना चाहिए ] "यह सुनिश्चित करने के लिए कि यह एक उचित सीमा से नीचे है। उदाहरण के लिए "Prime (Integer.MAX_VALUE)" पर कॉल करें और जब यह OutOfMemoryError फेंकता है तो एक बग दर्ज करें।
नौसरोबोट

28
@nicerobot: हल्का करें?
कैम

6
@nicerobot: वास्तव में, मैं इसे वापस लेता हूं। मैंने मूल रूप से इस प्रश्न की अकादमिक प्रकृति का अनुमान लगाया है कि इसका उपयोग केवल सीखने के उद्देश्यों के लिए किया गया है, और यह कि आप एक अप्रिय जुड़वाँ हैं। हालाँकि दूसरे विचार पर ऐसा नहीं है; यह कभी उल्लेख नहीं किया गया है या यहां तक ​​कि इस सवाल में निहित नहीं है कि रेगेक्स केवल सीखने के उद्देश्य के लिए है। वास्तव में मेरी पहली धारणा यह है कि यह बहुत सरल-दिखने वाला है जहाँ तक कोड स्निपेट्स जाते हैं, इसलिए एक शुरुआत वास्तव में यह मान सकती है कि इसका उपयोग अभ्यास में किया जा सकता है। +1।
कैम

7
@incrediman को कोई चिंता नहीं है। मैं देख सकता हूं कि आप ऐसा कैसे सोच सकते हैं। इसका उपयोग करने के परिणामों को चेतावनी देने के लिए केवल मेरा इरादा था, सीखने को हतोत्साहित करने के लिए नहीं कि यह कैसे काम करता है। एक साधारण "कृपया इसे तैनात न करें।" मेरी टिप्पणी के बाकी से पहले अपने प्रारंभिक परिप्रेक्ष्य से यह कम कृपालु लग रहा हो सकता है।
nicerobot

जवाबों:


120

आपने कहा कि आप इस हिस्से को समझते हैं, लेकिन सिर्फ जोर देने के लिए, उत्पन्न स्ट्रिंग में आपूर्ति की गई संख्या के बराबर लंबाई है। तो स्ट्रिंग में तीन वर्ण हैं यदि और केवल यदि n == 3

.?

रेगेक्स का पहला भाग कहता है, "कोई भी चरित्र, शून्य या एक बार"। तो मूल रूप से, वहाँ शून्य या एक चरित्र है - या, जो मैंने ऊपर उल्लेख किया है, के अनुसार n == 0 || n == 1। अगर हमारे पास मैच है, तो उस की उपेक्षा को वापस करें। यह इस तथ्य से मेल खाता है कि शून्य और एक प्रमुख नहीं हैं।

(..+?)\\1+

रेगेक्स का दूसरा भाग थोड़ा पेचीदा है, जो समूहों और बैकरेन्स पर निर्भर है। एक समूह कोष्ठक में कुछ भी होता है, जिसे बाद में उपयोग के लिए regex इंजन द्वारा कैप्चर और संग्रहीत किया जाएगा। एक बैकरेन्स एक मिलान समूह है जो बाद में उसी रेगेक्स में उपयोग किया जाता है।

समूह 1 वर्ण को पकड़ता है, फिर 1 या उससे अधिक वर्ण को। (+ वर्ण का अर्थ एक या एक से अधिक है, लेकिन केवल पिछले वर्ण या समूह का है। इसलिए यह "दो या चार या छः आदि वर्ण" नहीं है, बल्कि "दो या तीन आदि" + + जैसा है? यह संभव के रूप में कुछ वर्णों से मेल खाने की कोशिश करता है। + आम तौर पर अगर ऐसा हो सकता है, तो यह पूरे स्ट्रिंग को टटोलने की कोशिश करता है, जो इस मामले में बुरा है क्योंकि यह पीछे के हिस्से को काम करने से रोकता है।)

अगला भाग है पश्चगामी: वर्णों का वही सेट (दो या अधिक), फिर से दिखाई दे रहा है। कहा कि पश्चगामी एक या अधिक बार प्रकट होता है।

इसलिए। कब्जा कर लिया समूह वर्णों की एक प्राकृतिक संख्या (2 आगे से) पर कब्जा कर लिया है। कहा गया समूह तब कुछ प्राकृतिक संख्या (2 आगे से भी) प्रकट होता है। यदि कोई मैच है, तो इसका मतलब है कि n-लंबाई स्ट्रिंग से मेल खाने वाले 2 के बराबर या उससे अधिक दो संख्याओं का उत्पाद खोजना संभव है ... जिसका मतलब है कि आपके पास एक समग्र n है। इसलिए फिर से, सफल मैच की उपेक्षा: n प्रमुख नहीं है।

यदि कोई मिलान नहीं पाया जा सकता है, तो आप अपने उत्पाद को दो प्राकृतिक संख्याओं से अधिक या 2 के बराबर के साथ नहीं ला सकते हैं ... और आपके पास एक गैर-मिलान और एक अभाज्य दोनों हैं, इसलिए फिर से नकार की वापसी मैच के परिणाम के।

क्या आप इसे अभी देख रहे हैं? यह अविश्वसनीय रूप से मुश्किल है (और कम्प्यूटेशनल रूप से महंगा!), लेकिन यह एक ही समय में भी सरल है, एक बार जब आप इसे प्राप्त करते हैं। :-)

यदि आपके और प्रश्न हैं, तो मैं विस्तृत कर सकता हूं, जैसे कि रेक्सक्स पार्सिंग वास्तव में कैसे काम करता है। लेकिन मैं इस उत्तर को अभी (या जितना आसान हो सकता है) के लिए सरल रखने की कोशिश कर रहा हूं।


10
मैंने जेएस के साथ क्रोम देव कंसोल में इस तर्क की कोशिश की। वेब पेज पर। और जांच के लिए सिर्फ 5 पास हुए। पेज क्रैश हो गया!
अमोघ तलपलीकर

नीचे टिप्पणी बेहतर व्याख्या देती है। आगे बढ़ने से पहले कृपया इसे पढ़ें!
इवान डेविडोव

"बेहतर" व्यक्तिपरक है- मैं कहूंगा कि यह एक अलग कोण से समस्या का सामना करता है और इस उत्तर के लिए एक अद्भुत पूरक है। :-)
प्लैटिनम

1
मैंने वास्तव में एक ब्लॉग पोस्ट लिखा है जिसमें इस बारे में अधिक विस्तार से बताया गया है: नियमित अभिव्यक्ति की जाँच करना जो एक संख्या प्रधान है, तो चेक करना
इलिया गेरासिमचुक

73

मैं प्राक्षेपिक परीक्षण के बाहर रेगेक्स भाग की व्याख्या करूंगा: निम्नलिखित रेगेक्स, String sजिसे दोहराते हुए String tपाया जाता है, पाता है t

    System.out.println(
        "MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
    ); // prints "Mamamia"

जिस तरह से यह काम करता है वह यह है कि रेगेक्स कैप्चर करता (.*)है \1, और फिर देखता है कि क्या \1+इसके पीछे है। ^और का उपयोग करना$ यह सुनिश्चित करता है कि एक मैच पूरे स्ट्रिंग का होना चाहिए।

तो, एक तरह से, हमें दिया जाता है String s, जो "बहु" है String t, और रेगेक्स ऐसा t(सबसे लंबा संभव है, क्योंकि \1लालची है)।

एक बार जब आप समझ जाते हैं कि यह रेगेक्स क्यों काम करता है, तो (अब के लिए ओपी के रेक्स में पहले वैकल्पिक को अनदेखा करते हुए) यह समझाते हुए कि यह कैसे प्रायोगिक परीक्षण के लिए उपयोग किया जाता है, सरल है।

  • की शुद्धता का परीक्षण करने के लिए n, पहले एक Stringलंबाई n(उसी के साथ भरा char) उत्पन्न करें
  • रेगेक्स Stringकुछ लंबाई (कहते हैं k) को पकड़ता है \1, और \1+बाकी हिस्सों से मेल खाने की कोशिश करता हैString
    • यदि कोई मैच होता है, तो nएक उचित मल्टीपल है k, और इसलिए nप्राइम नहीं है।
    • यदि कोई मेल नहीं है, तो ऐसा कोई भी kमौजूद नहीं है जो विभाजित हो n, और nइसलिए एक प्रमुख है

.?|(..+?)\1+अभाज्य संख्याओं का मिलान कैसे होता है ?

वास्तव में, यह नहीं है! यह मेल खाता है String जिसकी लंबाई अभाज्य नहीं है!

  • .?: Stringलंबाई के प्रत्यावर्तन मैचों का पहला भाग 0या 1(परिभाषा द्वारा अभाज्य नहीं)
  • (..+?)\1+: प्रत्यावर्तन के दूसरे भाग, regex की भिन्नता ऊपर बताया गया है, मैचों Stringलंबाई की nहै कि एक के "एक बहु" Stringलंबाई की k >= 2(यानीn एक समग्र, नहीं एक प्रमुख है)।
    • ध्यान दें कि अनिच्छुक संशोधक ?वास्तव में शुद्धता के लिए आवश्यक नहीं है, लेकिन यह kपहले छोटे प्रयास करके प्रक्रिया को गति देने में मदद कर सकता है

बयान ! booleanमें पूरक ऑपरेटर पर ध्यान दें return: यह नकारात्मक करता है matches। यह तब होता है जब regex DOESN'T मैच होता है, nअभाज्य है! यह एक दोहरा नकारात्मक तर्क है, इसलिए कोई आश्चर्य नहीं कि यह भ्रमित करने जैसा है !!


सरलीकरण

यहाँ इसे और अधिक पठनीय बनाने के लिए कोड का एक सरल पुनर्लेखन है:

public static boolean isPrime(int n) {
    String lengthN = new String(new char[n]);
    boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
    return !isNotPrimeN;
}

ऊपर मूल रूप से मूल जावा कोड के समान है, लेकिन तर्क को समझने में आसान बनाने के लिए स्थानीय चर के असाइनमेंट के साथ कई बयानों में टूट गया।

हम इस प्रकार है, परिमित पुनरावृत्ति का उपयोग करके, रेगेक्स को भी सरल बना सकते हैं:

boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");

फिर से, एक Stringलंबाई दी गई n, उसी से भरा char,

  • .{0,1}जाँच करता है कि n = 0,1नहीं, प्रधान नहीं
  • (.{2,})\1+जाँच करता है कि nक्या एक उचित एकाधिक k >= 2, प्रमुख नहीं है

?पर अनिच्छुक संशोधक के अपवाद के साथ \1(स्पष्टता के लिए छोड़ दिया गया), उपरोक्त रेगेक्स मूल के समान है।


अधिक मज़ा रेगेक्स

निम्नलिखित रेगेक्स समान तकनीक का उपयोग करता है; यह शैक्षिक होना चाहिए:

System.out.println(
    "OhMyGod=MyMyMyOhGodOhGodOhGod"
        .replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"

यह सभी देखें


6
+1: मुझे लगता है कि मेरा दृष्टिकोण शायद मेरी तुलना में बेहतर था। मुझे नहीं पता कि मुझे इतने सारे अपवोट या चेक मार्क क्यों मिले ... आप इसके लायक हैं, मुझे लगता है। :-( क्षमा करें
प्लैटिनम एज़्योर

@ प्लैटिनम: वाह, मैंने कभी नहीं सोचा था कि आप सार्वजनिक रूप से यह कहते हुए घूमेंगे! सहायता का शुक्रिया। शायद मुझे इससे [Populist]कुछ दिन मिलेंगे ।
पॉलीजेन लुब्रिकेंट

2
खैर, यह सिर्फ सच है (जैसा कि मैं इसे समझता हूं) ... वास्तव में बहुत बड़ी बात नहीं है। मैं यहाँ प्रतिनिधि के लिए नहीं हूँ (हालाँकि यह हमेशा एक बोनस और सुखद आश्चर्य है) ... मैं यहाँ उन सवालों के जवाब देने की कोशिश कर रहा हूँ जब मैं कर सकता हूँ। इस प्रकार यह कोई आश्चर्य के रूप में नहीं आना चाहिए कि मैं स्वीकार कर सकता हूं जब किसी ने किसी विशेष प्रश्न में मुझसे बेहतर किया है।
प्लेटिनम एज़्योर

25

नाइस रेगेक्स ट्रिक (हालांकि बहुत अक्षम) ... :)

रेगेक्स गैर-primes को निम्नानुसार परिभाषित करता है:

N अभाज्य नहीं है अगर केवल N <= 1 या N कुछ K> 1 से विभाज्य है।

रेगेक्स इंजन के लिए एन के सरल डिजिटल प्रतिनिधित्व को पारित करने के बजाय, इसे एक दोहराए गए चरित्र से बना लंबाई एन के अनुक्रम के साथ खिलाया जाता है । एन = 0 या एन = 1 के लिए डिस्जंक्शन चेक का पहला भाग, और दूसरा बैकरेफरेंस का उपयोग करते हुए एक विभाजक के> 1 के लिए दिखता है। यह रेगेक्स इंजन को कुछ गैर खाली उप-अनुक्रम को खोजने के लिए मजबूर करता है जो अनुक्रम बनाने के लिए कम से कम दो बार दोहराया जा सकता है। यदि इस तरह की बाद की स्थिति मौजूद है, तो इसका मतलब है कि इसकी लंबाई एन को विभाजित करती है, इसलिए एन प्रमुख नहीं है।


2
अजीब तरह से पर्याप्त है, यहां तक ​​कि बार-बार दूसरे लम्बे और अधिक तकनीकी स्पष्टीकरणों को पढ़ने के बाद, मुझे यह स्पष्टीकरण ऐसा मिला जिसने इसे मेरे सिर में 'क्लिक' कर दिया।
आठ-बिट गुरु

2
/^1?$|^(11+?)\1+$/

बेस 1 (1 = 1, 2 = 11, 3 = 111, ...) में रूपांतरण के बाद संख्याओं पर लागू करें। गैर-primes यह मेल करेंगे। यदि यह मेल नहीं खाता है, तो यह प्रमुख है।

यहाँ स्पष्टीकरण ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.