सोर्स कोड
मेरे द्वारा नीचे पुनर्लेखन कार्यों के लिए स्रोत कोड यहां उपलब्ध है ।
जावा 7 में अपडेट करें
Pattern
जेडीके 7 के लिए सूर्य की अद्यतन कक्षा में एक अद्भुत नया झंडा है UNICODE_CHARACTER_CLASS
, जो सब कुछ फिर से काम करता है। यह (?U)
पैटर्न के अंदर एक एम्बेड के रूप में उपलब्ध है , इसलिए आप इसे String
क्लास के रैपर के साथ भी उपयोग कर सकते हैं । यह खेल विभिन्न अन्य गुणों के लिए भी परिभाषाओं को सही करता है। अब यह यूटीएस # 18: RL1.2 और RL1.2a दोनों से UTS # 18: यूनिकोड स्टैंडर्ड को ट्रैक करता है । यह एक रोमांचक और नाटकीय सुधार है, और इस महत्वपूर्ण प्रयास के लिए विकास टीम की सराहना की जानी है।
जावा की रेगेक्स यूनिकोड समस्याएं
जिसका अर्थ है - जावा regexes के साथ समस्या यह है कि पर्ल 1.0 charclass पलायन है \w
, \b
, \s
, \d
और उनके पूरक - जावा में यूनिकोड के साथ काम करने के लिए बढ़ाया नहीं हैं। इन लोगों के बीच अकेला, \b
कुछ विस्तारित अर्थ विज्ञान भी आनंद मिलता है, लेकिन इन नक्शा न करने के लिए \w
, और न ही करने के लिए यूनिकोड पहचानकर्ता , और न ही करने के लिए यूनिकोड लाइन ब्रेक गुण ।
इसके अतिरिक्त, जावा में POSIX गुण इस तरह से एक्सेस किए जाते हैं:
POSIX syntax Java syntax
[[:Lower:]] \p{Lower}
[[:Upper:]] \p{Upper}
[[:ASCII:]] \p{ASCII}
[[:Alpha:]] \p{Alpha}
[[:Digit:]] \p{Digit}
[[:Alnum:]] \p{Alnum}
[[:Punct:]] \p{Punct}
[[:Graph:]] \p{Graph}
[[:Print:]] \p{Print}
[[:Blank:]] \p{Blank}
[[:Cntrl:]] \p{Cntrl}
[[:XDigit:]] \p{XDigit}
[[:Space:]] \p{Space}
क्योंकि इसका मतलब चीजों की तरह है कि यह एक वास्तविक गड़बड़ है Alpha
, Lower
और Space
ऐसा नहीं यूनिकोड को जावा मानचित्र में Alphabetic
, Lowercase
या Whitespace
गुण। यह अत्यधिक कष्टप्रद है। जावा की यूनिकोड संपत्ति का समर्थन कड़ाई से विरोधाभासी है , जिसका अर्थ है कि यह पिछले दशक में बाहर निकली कोई यूनिकोड संपत्ति का समर्थन नहीं करता है।
व्हाट्सएप के बारे में ठीक से बात नहीं कर पाना सुपर-कष्टप्रद है। निम्न तालिका पर विचार करें। उन कोड बिंदुओं में से प्रत्येक के लिए, जावा के लिए J- परिणाम स्तंभ और Perl या किसी अन्य PCRE- आधारित regex इंजन के लिए P- परिणाम स्तंभ दोनों हैं:
Regex 001A 0085 00A0 2029
J P J P J P J P
\s 1 1 0 1 0 1 0 1
\pZ 0 0 0 0 1 1 1 1
\p{Zs} 0 0 0 0 1 1 0 0
\p{Space} 1 1 0 1 0 1 0 1
\p{Blank} 0 0 0 0 0 1 0 0
\p{Whitespace} - 1 - 1 - 1 - 1
\p{javaWhitespace} 1 - 0 - 0 - 1 -
\p{javaSpaceChar} 0 - 0 - 1 - 1 -
देखना है कि?
वस्तुतः उन जावा सफेद अंतरिक्ष परिणामों में से हर एक यूनिकोड के अनुसार ̲w̲r̲o̲n̲g one है। यह वास्तव में एक बड़ी समस्या है। जावा को केवल गड़बड़ किया गया है, जो मौजूदा अभ्यास के अनुसार और यूनिकोड के अनुसार "गलत" हैं। इसके अलावा जावा भी आपको वास्तविक यूनिकोड संपत्तियों तक पहुंच नहीं देता है! वास्तव में, जावा किसी भी संपत्ति का समर्थन नहीं करता है जो यूनिकोड व्हाट्सएप से मेल खाती है।
उन सभी समस्याओं का समाधान, और अधिक
इससे संबंधित और कई अन्य समस्याओं से निपटने के लिए, कल मैंने एक पैटर्न स्ट्रिंग को फिर से लिखने के लिए एक जावा फ़ंक्शन लिखा था जो इन 14 वर्णमाला के पलायन को फिर से लिखता है:
\w \W \s \S \v \V \h \H \d \D \b \B \X \R
उन्हें उन चीजों के साथ प्रतिस्थापित करके जो वास्तव में यूनिकोड को एक पूर्वानुमान और सुसंगत फैशन में मिलान करने के लिए काम करते हैं। यह एकल हैक सत्र से केवल एक अल्फा प्रोटोटाइप है, लेकिन यह पूरी तरह से कार्यात्मक है।
लघुकथा यह है कि मेरा कोड उन 14 को फिर से लिखता है:
\s => [\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]
\S => [^\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]
\v => [\u000A-\u000D\u0085\u2028\u2029]
\V => [^\u000A-\u000D\u0085\u2028\u2029]
\h => [\u0009\u0020\u00A0\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]
\H => [^\u0009\u0020\u00A0\u1680\u180E\u2000\u2001-\u200A\u202F\u205F\u3000]
\w => [\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]
\W => [^\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]
\b => (?:(?<=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])|(?<![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]))
\B => (?:(?<=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])|(?<![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]))
\d => \p{Nd}
\D => \P{Nd}
\R => (?:(?>\u000D\u000A)|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029])
\X => (?>\PM\pM*)
कुछ बातों पर गौर करना ...
यह इसकी \X
परिभाषा के लिए उपयोग करता है कि यूनिकोड अब एक विरासत ग्रेफेम क्लस्टर के रूप में संदर्भित करता है , न कि एक विस्तारित ग्रेफेम क्लस्टर के रूप में, जैसा कि बाद में अधिक जटिल है। पर्ल खुद अब फैन्सी संस्करण का उपयोग करता है, लेकिन पुराने संस्करण अभी भी सबसे आम स्थितियों के लिए पूरी तरह से काम कर रहे हैं। संपादित करें: नीचे देखें परिशिष्ट।
\d
आपके इरादे पर क्या करना है यह निर्भर करता है, लेकिन डिफ़ॉल्ट यूनीकोड परिभाषा है। मैं लोगों को हमेशा न चाहते हुए भी देख सकता हूं \p{Nd}
, लेकिन कभी-कभी [0-9]
या \pN
।
दो सीमा परिभाषाओं, \b
और \B
, विशेष रूप से \w
परिभाषा का उपयोग करने के लिए लिखे गए हैं ।
यह \w
परिभाषा व्यापक रूप से व्यापक है, क्योंकि यह परिक्रमा पत्रों को पकड़ती है न कि केवल परिक्रमा करने वालों को। Other_Alphabetic
JDK7 तक यूनिकोड संपत्ति उपलब्ध नहीं है, इसलिए यह सबसे अच्छा है जो आप कर सकते हैं।
सीमाओं की खोज
सीमाएँ तब से एक समस्या है जब लैरी वॉल ने पहली बार 1987 में पर्ल 1.0 के लिए उनके बारे में बात करने के लिए \b
और \B
वाक्यविन्यास गढ़ा था । यह समझने की कुंजी है कि कैसे \b
और \B
दोनों काम उनके बारे में दो व्यापक मिथकों को दूर करने के लिए हैं:
- वे कर रहे हैं ही कभी देख के लिए
\w
शब्द वर्ण, कभी नहीं गैर शब्द अक्षरों के लिए।
- वे विशेष रूप से स्ट्रिंग के किनारे की तलाश नहीं करते हैं।
एक \b
सीमा का मतलब है:
IF does follow word
THEN doesn't precede word
ELSIF doesn't follow word
THEN does precede word
और उन सभी को पूरी तरह से सीधे रूप में परिभाषित किया गया है:
- इस प्रकार शब्द है
(?<=\w)
।
- पछाड़ शब्द है
(?=\w)
।
- शब्द का अनुसरण नहीं करता है
(?<!\w)
।
- पूर्ववर्ती शब्द नहीं है
(?!\w)
।
इसलिए, चूंकि regexes में IF-THEN
एक and
एड-साथ AB
में एन्कोड किया गया है , एक or
है X|Y
, और क्योंकि and
पूर्व की तुलना में अधिक है or
, जो कि बस है AB|CD
। तो \b
इसका मतलब है कि हर सीमा को सुरक्षित रूप से बदला जा सकता है:
(?:(?<=\w)(?!\w)|(?<!\w)(?=\w))
\w
उचित तरीके से परिभाषित के साथ ।
(आप सोच सकते हैं कि यह अजीब है A
और C
घटक विपरीत हैं। एक आदर्श दुनिया में, आपको वह लिखने में सक्षम होना चाहिए AB|D
, लेकिन थोड़ी देर के लिए मैं यूनिकोड गुणों में आपसी बहिष्करण विरोधाभास का पीछा कर रहा था - जो मुझे लगता है कि मैंने ध्यान रखा है , लेकिन मैंने केवल मामले में सीमा में दोहरी स्थिति को छोड़ दिया। इसके अलावा अगर आप बाद में अतिरिक्त विचार प्राप्त करते हैं तो यह अधिक व्यापक है।)
के लिए \B
गैर सीमाओं, तर्क है:
IF does follow word
THEN does precede word
ELSIF doesn't follow word
THEN doesn't precede word
के \B
साथ प्रतिस्थापित किए जाने वाले सभी उदाहरणों की अनुमति :
(?:(?<=\w)(?=\w)|(?<!\w)(?!\w))
यह वास्तव में कैसे \b
और \B
व्यवहार है। उनके लिए समतुल्य पैटर्न हैं
\b
((IF)THEN|ELSE)
निर्माण का उपयोग करना है(?(?<=\w)(?!\w)|(?=\w))
\B
((IF)THEN|ELSE)
निर्माण का उपयोग करना है(?(?=\w)(?<=\w)|(?<!\w))
लेकिन अभी वाले संस्करण AB|CD
ठीक हैं, खासकर यदि आप अपनी regex भाषा में सशर्त पैटर्न की कमी रखते हैं - जैसे जावा। ☹
मैंने पहले से ही एक परीक्षण सूट के साथ सभी तीन समान परिभाषाओं का उपयोग करते हुए सीमाओं के व्यवहार को सत्यापित किया है जो प्रति रन 110,385,408 मैचों की जांच करता है, और जो मैंने एक दर्जन अलग-अलग डेटा कॉन्फ़िगरेशनों के अनुसार चलाया है:
0 .. 7F the ASCII range
80 .. FF the non-ASCII Latin1 range
100 .. FFFF the non-Latin1 BMP (Basic Multilingual Plane) range
10000 .. 10FFFF the non-BMP portion of Unicode (the "astral" planes)
हालांकि, लोग अक्सर एक अलग तरह की सीमा चाहते हैं। वे कुछ ऐसा चाहते हैं जो व्हाट्सएप और एज-ऑफ-स्ट्रिंग जागरूक हो:
- के रूप में छोड़ दिया है
(?:(?<=^)|(?<=\s))
- दाहिने किनारे के रूप में
(?=$|\s)
जावा के साथ जावा फिक्सिंग
मैंने अपने दूसरे उत्तर में जो कोड पोस्ट किया है, वह इसे प्रदान करता है और काफी कुछ अन्य उपयुक्तताएं देता है। इसमें प्राकृतिक-भाषा के शब्द, डैश, हाइफ़न और एपोस्ट्रोफ़ के लिए परिभाषाएँ शामिल हैं, साथ ही थोड़ा और अधिक।
यह आपको यूनिकोड वर्णों को तार्किक कोड बिंदुओं में निर्दिष्ट करने की अनुमति देता है, न कि अज्ञात यूटीएफ -16 सरोगेट्स में। यह कितना कठिन है, यह समझना कठिन है! और यह सिर्फ स्ट्रिंग विस्तार के लिए है।
रेगेक्स चारक्लास प्रतिस्थापन के लिए जो आपके जावा रेगेक्स में चारकल बनाता है अंत में यूनिकोड पर काम करता है, और सही ढंग से काम करता है, यहां से पूर्ण स्रोत को पकड़ो । आप इसके साथ कृपया कर सकते हैं, कृपया। यदि आप इसे ठीक करते हैं, तो मुझे यह सुनना अच्छा लगेगा, लेकिन आपको ऐसा नहीं करना चाहिए। यह बहुत छोटा है। मुख्य regex पुनर्लेखन समारोह की हिम्मत सरल है:
switch (code_point) {
case 'b': newstr.append(boundary);
break; /* switch */
case 'B': newstr.append(not_boundary);
break; /* switch */
case 'd': newstr.append(digits_charclass);
break; /* switch */
case 'D': newstr.append(not_digits_charclass);
break; /* switch */
case 'h': newstr.append(horizontal_whitespace_charclass);
break; /* switch */
case 'H': newstr.append(not_horizontal_whitespace_charclass);
break; /* switch */
case 'v': newstr.append(vertical_whitespace_charclass);
break; /* switch */
case 'V': newstr.append(not_vertical_whitespace_charclass);
break; /* switch */
case 'R': newstr.append(linebreak);
break; /* switch */
case 's': newstr.append(whitespace_charclass);
break; /* switch */
case 'S': newstr.append(not_whitespace_charclass);
break; /* switch */
case 'w': newstr.append(identifier_charclass);
break; /* switch */
case 'W': newstr.append(not_identifier_charclass);
break; /* switch */
case 'X': newstr.append(legacy_grapheme_cluster);
break; /* switch */
default: newstr.append('\\');
newstr.append(Character.toChars(code_point));
break; /* switch */
}
saw_backslash = false;
वैसे भी, वह कोड सिर्फ एक अल्फा रिलीज है, सामान जिसे मैंने सप्ताहांत में हैक किया था। यह उस तरह से नहीं रहेगा।
बीटा के लिए मेरा इरादा है:
कोड दोहराव के साथ गुना
रीसैक्स एक्सैड्स बनाम एसेडिंग स्ट्रिंग एस्केप्स के बारे में एक स्पष्ट इंटरफ़ेस प्रदान करता है
\d
विस्तार में कुछ लचीलापन प्रदान करते हैं , और शायद\b
सुविधा विधियाँ प्रदान करें जो आपके चारों ओर घूमती हैं और आपके लिए Pattern.compile या String.matches या whatnot को कॉल करती हैं
उत्पादन रिलीज के लिए, इसमें javadoc और JUnit परीक्षण सूट होना चाहिए। मैं अपना गीगाटेस्टर शामिल कर सकता हूं, लेकिन इसे JUnit परीक्षणों के रूप में नहीं लिखा गया है।
परिशिष्ट
मेरे पास अच्छी खबर भी और बुरी खबर भी है।
अच्छी खबर यह है कि मैं अब एक बेहतर के लिए उपयोग करने के लिए एक विस्तारित अंगूर क्लस्टर के लिए एक बहुत करीब सन्निकटन मिला है ।\X
बुरी खबर यह है कि यह पैटर्न है:
(?:(?:\u000D\u000A)|(?:[\u0E40\u0E41\u0E42\u0E43\u0E44\u0EC0\u0EC1\u0EC2\u0EC3\u0EC4\uAAB5\uAAB6\uAAB9\uAABB\uAABC]*(?:[\u1100-\u115F\uA960-\uA97C]+|([\u1100-\u115F\uA960-\uA97C]*((?:[[\u1160-\u11A2\uD7B0-\uD7C6][\uAC00\uAC1C\uAC38]][\u1160-\u11A2\uD7B0-\uD7C6]*|[\uAC01\uAC02\uAC03\uAC04])[\u11A8-\u11F9\uD7CB-\uD7FB]*))|[\u11A8-\u11F9\uD7CB-\uD7FB]+|[^[\p{Zl}\p{Zp}\p{Cc}\p{Cf}&&[^\u000D\u000A\u200C\u200D]]\u000D\u000A])[[\p{Mn}\p{Me}\u200C\u200D\u0488\u0489\u20DD\u20DE\u20DF\u20E0\u20E2\u20E3\u20E4\uA670\uA671\uA672\uFF9E\uFF9F][\p{Mc}\u0E30\u0E32\u0E33\u0E45\u0EB0\u0EB2\u0EB3]]*)|(?s:.))
जावा में आप किस रूप में लिखेंगे:
String extended_grapheme_cluster = "(?:(?:\\u000D\\u000A)|(?:[\\u0E40\\u0E41\\u0E42\\u0E43\\u0E44\\u0EC0\\u0EC1\\u0EC2\\u0EC3\\u0EC4\\uAAB5\\uAAB6\\uAAB9\\uAABB\\uAABC]*(?:[\\u1100-\\u115F\\uA960-\\uA97C]+|([\\u1100-\\u115F\\uA960-\\uA97C]*((?:[[\\u1160-\\u11A2\\uD7B0-\\uD7C6][\\uAC00\\uAC1C\\uAC38]][\\u1160-\\u11A2\\uD7B0-\\uD7C6]*|[\\uAC01\\uAC02\\uAC03\\uAC04])[\\u11A8-\\u11F9\\uD7CB-\\uD7FB]*))|[\\u11A8-\\u11F9\\uD7CB-\\uD7FB]+|[^[\\p{Zl}\\p{Zp}\\p{Cc}\\p{Cf}&&[^\\u000D\\u000A\\u200C\\u200D]]\\u000D\\u000A])[[\\p{Mn}\\p{Me}\\u200C\\u200D\\u0488\\u0489\\u20DD\\u20DE\\u20DF\\u20E0\\u20E2\\u20E3\\u20E4\\uA670\\uA671\\uA672\\uFF9E\\uFF9F][\\p{Mc}\\u0E30\\u0E32\\u0E33\\u0E45\\u0EB0\\u0EB2\\u0EB3]]*)|(?s:.))";
¡Tschüss!