- Python
reमें$, multiline mode बंद होने पर भी, सिर्फ string के अंत पर ही नहीं बल्कि अंत में मौजूद आखिरी newline के ठीक पहले भी match कर सकता है - सिर्फ इसलिए कि
^“string की शुरुआत” जैसा दिखता है, यह मान लेना सही नहीं कि$भी पूरी तरह symmetric तरीके से काम करेगा; इसका वास्तविक मतलब regex implementation के अनुसार बदलता है "cat\n"पर$,\z,\Zके नतीजे PHP, ECMAScript, Python, Go, Java 8, .NET 7.0, Rust में एक-दूसरे से अलग हैं, और Python का\zPython 3.14 में नया जोड़ा गया है- अगर अंत का newline स्वीकार्य है, तो multiline mode का
$तालिका के सभी platforms पर"cat\n"से match करता है, लेकिन newline को छोड़कर सिर्फ अंत से match करना हो तो syntax का चुनाव बदल जाता है - अगर आखिरी newline से match नहीं करना है, तो ज़्यादातर platforms में
\zका उपयोग किया जाता है, और Python 3.14 से पहले तथा ECMAScript में अलग-अलग विकल्पों पर विचार करना पड़ता है
Python re में $ कहाँ match करता है
- Python regex module
reमें$, multiline mode बंद होने पर भी, string के अंत या string के अंत में मौजूद आखिरी newline के ठीक पहले match कर सकता है cat$,"lolcat"से match होता है और"internet cat video"से match नहीं होता, इसलिए यह सरल लग सकता है, लेकिन"cat\n"जैसी trailing newline वाली string में नतीजा उम्मीद से अलग हो सकता हैre.MULTILINEदेने पर$, string के अंत और हर line के अंत, यानी हर newline के ठीक पहले, match करता है- default behavior में भी
$string के अंत से match करता है, और अगर string के अंत में newline है तो उस newline के ठीक पहले भी match करता है
आखिरी newline को छोड़कर match करना
- अगर सख्ती से सिर्फ string के अंत से match करना है, तो सिर्फ
$काफी नहीं हो सकता, और\zव\Zend anchors के उम्मीदवार बनते हैं - Python regex documentation और दूसरे regex syntax विवरण के आधार पर, implementation के अनुसार
\zऔर\Zका support और अर्थ अलग-अलग होता है "cat\n"के लिए अंतर इस प्रकार है- PHP:
"cat$"multiline हो या न हो, match करता है;"cat\z"match नहीं करता, और"cat\Z"match करता है - ECMAScript: multiline
"cat$"match करता है, लेकिन non-multiline"cat$"match नहीं करता;\zऔर\Zsupported नहीं हैं - Python:
"cat$"multiline हो या न ho, match करता है;"cat\z"और"cat\Z","cat\n"से match नहीं करते - Go और Rust: multiline
"cat$"match करता है, लेकिन non-multiline"cat$"और"cat\z"match नहीं करते;\Zsupported नहीं है - Java 8 और .NET 7.0:
"cat$"multiline हो या न हो, match करता है;"cat\z"match नहीं करता, और"cat\Z"match करता है
- PHP:
- Python का
\z, Python 3.14 में नया जोड़ा गया, और इससे पहले के versions में supported नहीं था - अगर अंत का newline स्वीकार्य है, तो multiline mode का
$तालिका के सभी platforms में लगातार"cat\n"से match करता है - अगर अंत के newline से match नहीं करना है, तो ज़्यादातर platforms में
\zका उपयोग करना चाहिए; Python 3.14 से पहले\Z, और ECMAScript में non-multiline$का उपयोग करना होगा - तालिका का data regex101.com से लिया गया था, और इसे वास्तविक runtime में test नहीं किया गया था
1 टिप्पणियां
Hacker News टिप्पणियाँ
मैं पहले से
^को “लाइन की शुरुआत” और$को “लाइन का अंत” मानता आया हूँregex के साथ काम करते समय टेक्स्ट को लाइन-दर-लाइन प्रोसेस करना बहुत आम है, इसलिए नतीजा अक्सर एक जैसा ही होता है, लेकिन इन ऑपरेटरों के बारे में सोचने का मेरा तरीका अब भी “string” से ज़्यादा “line” के करीब है
शायद
grepके जरिए regex सीखा, इसलिए input को string नहीं बल्कि line के रूप में देखने की आदत पड़ गईलगभग 20 साल से regex इस्तेमाल कर रहा हूँ, लेकिन
$को string का अंत कहा जाता है, यह शायद पहली बार सुन रहा हूँ; मैं इसे हमेशा line के अंत के रूप में ही सोचता रहा हूँ^को “string की शुरुआत” कहना खटकता हैअसल में जैसे
$“line का अंत” है, वैसे ही^भी “लाइन की शुरुआत” है, और string की शुरुआत\A, string का अंत\Zके ज़्यादा करीब लगता है$डिफ़ॉल्ट रूप से string के अंत के लिए एक positive lookahead assertion की तरह काम करता हैयह newline character को match करके consume नहीं करता
केवल multiline mode में newline की जगह पर match होता है, लेकिन तब भी शायद उसे consume नहीं करता
वास्तव में
$का इस्तेमाल करके ऐसा regex नहीं बना पाया जो एक line के आख़िरी character को capture करे, फिर newline को consume करे और अगली line के पहले character को capture करे; capture group बस$पर ही खत्म हो जाता हैgrepसे ज़्यादा Vim ने बैठाईPOSIX regex और Python regex अलग हैं
सामान्य तौर पर regex syntax सार्वभौमिक नहीं होती, इसलिए जिस implementation का इस्तेमाल कर रहे हों, उसके docs देखने चाहिए
POSIX अध्याय 9 के अनुसार regex strings पर काम करते हैं, लेकिन कुछ utilities processing को line-based तक सीमित करती हैं
साथ ही,
$को उस anchor के रूप में बताया गया है जो match की जा रही string के अंत पर स्थिर रहता है, इसलिए आखिर$string के अंत का मतलब देगा या line के अंत का, यह utility या mode तय करता हैgrep,sed,awk, Python जैसे आम tools डिफ़ॉल्ट रूप से line-based काम करते हैं, इसलिए आमतौर पर इसे line के अंत के रूप में लिया जाता हैएक ही सार्वभौमिक regex syntax जैसी कोई चीज़ नहीं है
जब तक यह न पता हो कि कौन-सी language और कौन-से options इस्तेमाल हो रहे हैं, regex को भरोसेमंद ढंग से पढ़ना या लिखना संभव नहीं
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1...
इस विषय पर Robert Elder से अपरिचित लोगों को उनसे परिचित कराने का यह बढ़िया मौका है
वह YouTube और अपने ब्लॉग पर अच्छा content बनाते हैं, और regex series में अलग-अलग tools द्वारा implement किए गए regex behavior के अंतर को काफ़ी गहराई से समझाते हैं
हाल का वीडियो भी अच्छा है: https://www.youtube.com/watch?v=ys7yUyyQA-Y
HN पाठकों की रुचि के लायक content भी बहुत है, और consulting की वास्तविकता व मुश्किलों जैसे विषय भी कवर करते हैं
https://www.youtube.com/@RobertElderSoftware
https://blog.robertelder.org/
https://blog.robertelder.org/regular-expressions/
https://www.youtube.com/watch?v=cK87ktENPrI
जब मैंने Perl सीखा, तब regex उन पहली चीज़ों में से थी जो सच में मेरे हाथ में बैठ गईं, और आज भी “Camel” किताब की वजह से Perl दिल के एक कोने में आराम से बसा है
अब सबसे अहम समझ यह है कि हर implementation अलग होती है, इसलिए जब भी कुछ काम करना होता है, मैं उस implementation की reference sheet निकालकर देखता हूँ
उदाहरण के लिए Emacs regex में
\wजैसे word character का support नहीं है और\s_-जैसी character class इस्तेमाल करनी पड़ती है, जो परेशान करती है, लेकिन documentation और discoverability के मामले में Emacs मुझे सबसे बेहतर लगता हैकुछ utilities में parentheses को escape करना पड़ता है और कुछ में नहीं, और कहीं यह behavior configurable होता है, कहीं नहीं
उलझन, झुंझलाहट और इनकार—सब चरणों से गुजर चुका हूँ, अब बस इसे स्वीकार कर लिया है
concept हर जगह वही रहता है, लेकिन dialect बदल जाती है
खासकर shell में,
sed/grep/awkGNU हैं या BSD, यह याद रखने से कहीं ज़्यादा मैं pipeline मेंperlजोड़ देना पसंद करता हूँPerl तो ऐसा दिखता है जैसे बिल्ली कीबोर्ड पर चल गई हो
ऐसा लगता है जैसे अनगिनत ख़राब hiring managers अब “regex में string के अंत को कैसे match करेंगे?” को अपनी trap question सूची में जोड़ रहे हों
regex से जुड़ी सूची में Perl को छोड़ना अजीब है
perlredocs में$को यूँ समझाया गया है: यह string के अंत से match करता है, या string के अंत में मौजूद newline से पहले match करता है, या/mके साथ किसी भी newline से पहले match करता हैशायद इसका मतलब यह भी है कि आजकल Perl लोगों के ध्यान से काफ़ी बाहर हो गई है
Raku, जिसे पहले Perl 6 कहा जाता था, में
^और$को string की शुरुआत/अंत के लिए तय किया गया, और^^व$$को line की शुरुआत/अंत के लिए जोड़ा गयाइसमें multiline mode नहीं है, और उसकी ज़रूरत भी नहीं पड़ती
\hhorizontal whitespace के लिए है, और\vvertical whitespace के लिएइसे पूरी तरह दोबारा सोचकर और फिर से लिखने की वजह से, पुराने behavior से लोगों को जो हैरानी होती थी उससे सीखने का फ़ायदा मिला
ऐसा लगता है जैसे दशकों में सीखी हुई line noise जैसी syntax को यूँ ही मिलाकर रख दिया गया हो
साफ़ तौर पर default इसका उल्टा होना चाहिए था
^और$को line के लिए, और^^व$$को string के लिए इस्तेमाल करना ज़्यादा स्वाभाविक लगताक्योंकि यह
^^line1$\n^line2$\n^line3$\n$जैसा दिखता हैऊपर से Perl 6 हर जगह नहीं है, लेकिन Perl 5 हर जगह है
^^,^से ज़्यादा “शुरुआत-जैसा” दिखता हैआम तौर पर processing के लिए regex में line डाली जाती है, इसलिए पूरे string के लिए single
^और$चुनना कुछ हद तक backward compatibility बनाए रखता हैमुझे नहीं लगता कि regex को standardized मानने वाले बहुत लोग होंगे
हर नए environment में जाने पर इसे फिर से सीखना पड़ा है
और भी regex dialects होंगे, लेकिन उनसे सामना नहीं होता, और जो मुझे पता हैं उनसे ज़्यादातर काम हो जाता है
यह rental car चलाने जैसा है
वह मेरी अपनी car से थोड़ा अलग चलती है, कुछ features नहीं होते और कुछ extra होते हैं, लेकिन कुल मिलाकर ज़्यादातर चीज़ें काफ़ी मिलती-जुलती हैं
इसलिए कम से कम मैं तो regex को कई सार्वजनिक आधिकारिक standards में standardized मानता हूँ
https://open-std.org/jtc1/sc22/…
https://pubs.opengroup.org/onlinepubs/9699919799/…
https://262.ecma-international.org/14.0/…
JavaScript सहित कई systems ने PCRE implement किया, क्योंकि Perl ने POSIX ढाँचे में कई उपयोगी extensions जोड़े
मुझे याद था कि RE2 का उद्देश्य मौजूदा systems की performance समस्याओं और अजीब behavior को सीमित करना था, और मैं समझता था कि यह पूरा का पूरा Go में implement किया गया था
बाद में पता चला कि RE2, Go से पहले आया था
फिर भी
$का अर्थ और multiline mode में बदलने का तरीका आम तौर पर काफ़ी consistent रहता हैलोग string और line को गड़बड़ा रहे हैं
string, characters का एक sequence है, और line को दो तरीकों से देखा जा सकता है
अगर newline को line terminator मानें, तो line शून्य या अधिक non-newline characters के बाद newline लगने से बनती है, और अगर अंत में newline नहीं है तो वह complete line नहीं है
POSIX यही नज़रिया अपनाता है
अगर newline को line separator मानें, तो line शून्य या अधिक non-newline characters का sequence है
किसी भी स्थिति में, line का content newline से पहले समाप्त होता है
^और$की semantics, चाहे single-line mode हो या multiline mode, line-based हैंstring-based semantics में, या फ़ाइलों के मामले में कहें तो whole-file semantics में,
\Aऔर\Zया उनके equivalent का इस्तेमाल करना चाहिएदोनों व्याख्याओं के अपने फ़ायदे हैं
serial connection से text भेजते समय newline को line terminator मानने पर यह जानना आसान होता है कि complete line मिली या नहीं
text files में newline को line separator मानना सुविधाजनक हो सकता है क्योंकि तब आख़िरी line invalid state में नहीं जाती, लेकिन line terminator रखने पर अधूरी लिखी गई line को पहचानना संभव होता है
इसी वजह से Ruby-based apps में कई बार गंभीर bugs आए हैं
हमेशा
\A\zका इस्तेमाल करना चाहिएhttps://homakov.blogspot.com/2012/05/saferweb-injects-in-var...
https://sakurity.com/blog/2015/02/28/openuri.html
https://sakurity.com/blog/2015/06/04/mongo_ruby_regexp.html