2025, Oct 15 14:04

Python में Unicode दशमलव अंकों के साथ int() कैसे काम करता है

जानें क्यों Python का int() केवल ASCII नहीं, Unicode दशमलव अंकों को भी पार्स करता है: ᪐᭒ → 2 का डेमो, CPython की मैपिंग का संक्षेप, और ASCII-केवल वैधता टिप्स।

Python में स्ट्रिंग्स को पूर्णांकों में बदलते समय, हममें से ज़्यादातर मान लेते हैं कि केवल ASCII अंक ही शामिल होते हैं। यह मान्यता तभी टूटती है जब आप दूसरी लिपियों के Unicode अंकों से सामना करते हैं। एक छोटा-सा लेकिन चौंकाने वाला उदाहरण: ᪐᭒ जैसी स्ट्रिंग को int() में देने पर नतीजा 2 आता है। लगता है मानो इनपुट में कोई संख्या नहीं, फिर भी Python सहजता से एक वैध पूर्णांक लौटा देता है।

इसे खुद आज़माकर देखें

नीचे दिया गया क्रम इस व्यवहार को शुरू से अंत तक दिखाता है: कच्चे बाइट्स, कोड प्वाइंट्स, और int() का परिणाम।

sample = '᪐᭒'
raw_bytes = bytes(sample, 'utf-8')
hex_points = [f'U+{ord(ch):04X}' for ch in sample]
value = int(sample)
print(raw_bytes)
print(hex_points)
print(value)

यह UTF-8 बाइट्स, कोड प्वाइंट्स U+1A90 और U+1B52, और अंत में संख्या 2 प्रिंट करेगा।

आखिर हो क्या रहा है

यह स्ट्रिंग कोई मनमाना पाठ नहीं है। दोनों अक्षर Unicode के दशमलव अंक हैं। पहला, ᪐ (U+1A90), Tai Tham Tham Digit Zero है। दूसरा, ᭒ (U+1B52), Balinese Digit Two है। Python की int() विनिर्देश के अनुसार, “0–9 के मान किसी भी Unicode दशमलव अंक द्वारा दर्शाए जा सकते हैं।” यानी Python केवल ASCII 0–9 ही नहीं, बल्कि Unicode Decimal Number वर्ग के अंकों को पहचानता है।

यही वजह है कि int('᪐᭒') वस्तुतः int('02') के बराबर है, जो 2 देता है।

CPython इसे अंदरूनी तौर पर कैसे संभालता है

अंदर के स्तर पर, CPython स्ट्रिंग-से-पूर्णांक रूपांतरण को पहले इनपुट को सामान्यीकृत करने वाली एक रूटीन से गुजारता है। इस प्रक्रिया में दशमलव-अंक गुण वाले किसी भी कोड प्वाइंट को उसके समकक्ष ASCII अंक में बदला जाता है, रिक्त स्थानों को ASCII स्पेस में मैप किया जाता है, और जो गैर-ASCII वर्ण न तो अंक हैं न स्पेस, उन्हें (पहले ऐसे वर्ण से शुरू करते हुए) ? से प्रतिस्थापित कर दिया जाता है। चुने गए आधार में वास्तविक पार्सिंग इसी सामान्यीकरण के बाद होती है।

Python के Unicode डेटाबेस की मदद से आप इस अंक-मैपिंग चरण का अंदाज़ा लगा सकते हैं:

import unicodedata as ud
example = '᪐᭒'
print([ud.digit(ch, "?") for ch in example])

यह 0 और 2 लौटाता है, जो दिखाता है कि वे अक्षर दशमलवी अंक की तरह व्याख्यायित होते हैं।

क्या int() सभी भाषाओं को स्कैन करता है?

यह हर अंक-प्रणाली को बलपूर्वक खोजता नहीं है। इसके बजाय, हर वर्ण को उसके Unicode गुणों के आधार पर देखा जाता है। यदि कोई वर्ण दशमलव अंक के रूप में वर्गीकृत है, तो उसका संख्यात्मक मान ज्ञात होता है और उसी अनुरूप मैप किया जाता है। यदि नहीं, तो उसे दशमलव अंक नहीं माना जाता। इसका अर्थ यह भी है कि int() अलग-अलग लिपियों के दशमलव अंकों के साथ काम करता है, लेकिन Unicode में गैर-दशमलव संख्या प्रणालियों पर विफल रहेगा।

समाधान: पार्सर नहीं, अपनी अपेक्षाएँ समायोजित करें

यदि आप int('᪐᭒') को 2 लौटाते देखते हैं और असफलता की उम्मीद करते हैं, तो समाधान है कि अपनी अपेक्षाएँ Python के प्रलेखित व्यवहार के अनुरूप करें। भाषा 0–9 के लिए किसी भी Unicode दशमलव अंक को स्वीकार करती है। अवधारणात्मक रूप से, Python पहले उन अंकों को उनके ASCII समकक्षों में अनुवादित करता है और फिर परिणाम को पार्स करता है। यदि आप वही मैपिंग स्पष्ट रूप से देखना चाहते हैं, तो ऊपर दिखाया गया unicodedata वाला त्वरित निरीक्षण इस रूपांतरण को सामने ले आएगा।

स्पष्टता के लिए, इनपुट से वैल्यू तक का एक संक्षिप्त डेमो:

text = '᪐᭒'
print([f'U+{ord(c):04X}' for c in text])  # ['U+1A90', 'U+1B52']
print(int(text))                           # 2

इंजीनियरों के लिए यह क्यों मायने रखता है

पहला, शुद्धता: जो कोड केवल ASCII अंकों को मान कर चलता है, वह Unicode इनपुट आने पर अलग तरह से बर्ताव करेगा। Python का यह व्यवहार सोचा-समझा और मानकों पर आधारित है, जो अंतरराष्ट्रीय पाठ संसाधित करते समय खास मायने रखता है।

दूसरा, प्रदर्शन पर असर पड़ता है। Unicode भर में अंकों की जाँच करने के लिए Unicode मेटाडेटा का सहारा लेना पड़ता है, और यह स्वाभाविक रूप से ऐसे कसे हुए ASCII परीक्षण (जैसे 48 <= ord(c) < 58) से धीमा है। यही वजहों में से एक है कि Python 3 की फुल-Unicode स्ट्रिंग्स कुछ स्थितियों में ASCII-केंद्रित लॉजिक से धीमी महसूस हो सकती हैं। आपको वैश्विक टेक्स्ट हैंडलिंग की शुद्धता मिलती है, जिसकी लागत आम तौर पर भीतर अनुकूलित होती है, पर पूरी तरह शुद्ध ASCII फास्ट-पाथ जितनी नहीं हो सकती।

मुख्य बातें

Python का int() केवल ASCII नहीं, बल्कि किसी भी Unicode दशमलव अंक को स्वीकार करता है। ᪐ और ᭒ जैसे अक्षर अपनी-अपनी लिपियों में वैध अंक हैं और पार्सिंग के दौरान क्रमशः 0 और 2 में मैप हो जाते हैं, इसलिए int('᪐᭒') वैसा ही व्यवहार करता है जैसा int('02')। दुभाषिया सभी भाषाएँ नहीं खंगालता; वह अंक-मूल्य तय करने के लिए Unicode गुणों पर निर्भर करता है। यदि पार्सिंग तर्क को लिपि-निरपेक्ष और अंतरराष्ट्रीय डाटा पर सही रखना है, तो यह एक सुविधा है। और यदि कोड को केवल ASCII अंकों को ही स्वीकार करना हो, तो इनपुट बाधाएँ और वैधता जाँच स्पष्ट रूप से लागू करें। इस व्यवहार की जानकारी कार्यक्षमता और प्रदर्शन—दोनों में अप्रत्याशितताओं से बचाती है।

यह लेख StackOverflow के एक प्रश्न (लेखक: Wör Du Schnaffzig) और jonrsharpe के उत्तर पर आधारित है।