std::string को लोअर केस में बदलना: C++ के अंदर की बात

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

केस का जादू: एक सरल प्रश्न कैसे पौराणिक बन गया

\n\n

कल्पना करें: आप C++ में एक प्रोग्राम लिख रहे हैं जो उपयोगकर्ताओं के नामों की तुलना करता है। लेकिन "John", "john" और "JOHN" एक ही व्यक्ति हैं, है ना? या आप एक कॉन्फ़िगरेशन फ़ाइल पार्स कर रहे हैं, जहाँ कुंजियाँ किसी भी केस में लिखी जा सकती हैं। और तब आप एक प्रतीत होने वाला बुनियादी प्रश्न पूछते हैं: "std::string को लोअर केस में कैसे बदलें?"

\n\n

इस प्रश्न ने Stack Overflow पर सैकड़ों हज़ारों बार देखा गया और दर्जनों उत्तर मिले। क्यों? क्योंकि C++ में स्ट्रिंग को लोअर केस में बदलना केवल एक फ़ंक्शन को कॉल करना नहीं है। यह एक पूरी दुनिया है जहाँ लोकेल, एन्कोडिंग, प्रदर्शन और मानक लाइब्रेरी मिलते हैं। इस लेख में हम अंदर की बात देखेंगे और समझेंगे कि यह ऑपरेशन वास्तव में कैसे काम करता है।

\n\n

क्लासिक उत्तर: std::transform + std::tolower

\n\n

यदि आपने "C++ string lower case example" गूगल किया है, तो आपने शायद यह कोड स्निपेट देखा होगा:

\n\n
#include <algorithm>\n#include <cctype>\n#include <string>\n\nstd::string to_lower_case(const std::string& str) {\n    std::string result = str;\n    std::transform(result.begin(), result.end(), result.begin(),\n                   [](unsigned char c) { return std::tolower(c); });\n    return result;\n}
\n\n

यह कोड काम करता है, लेकिन यह केवल हिमशैल का सिरा है। आइए इसे विस्तार से समझते हैं।

\n\n

unsigned char क्यों, char क्यों नहीं?

\n\n

शुरुआती लोगों की सबसे आम गलती std::tolower में char प्रकार का मान पास करना है। दरअसल, <cctype> का std::tolower int स्वीकार करता है और उम्मीद करता है कि मान unsigned char के रूप में प्रस्तुत करने योग्य हो (या EOF के बराबर हो)। यदि आप char का ऋणात्मक मान पास करते हैं (और कुछ कार्यान्वयनों में char साइन किया हुआ होता है), तो व्यवहार अपरिभाषित (undefined behavior) होगा।

\n\n

यही कारण है कि हम unsigned char के साथ लैम्ब्डा का उपयोग करते हैं:

\n
[](unsigned char c) { return std::tolower(c); }
\n\n

यह सुनिश्चित करता है कि हम स्वीकार्य मानों की सीमा से बाहर न जाएँ।

\n\n

विकल्प: for लूप

\n\n

कुछ डेवलपर अधिक स्पष्ट दृष्टिकोण पसंद करते हैं:

\n\n
std::string to_lower_case_for(const std::string& str) {\n    std::string result;\n    result.reserve(str.size());\n    for (char ch : str) {\n        result.push_back(std::tolower(static_cast<unsigned char>(ch)));\n    }\n    return result;\n}
\n\n

यह संस्करण थोड़ा कम सुरुचिपूर्ण है, लेकिन अर्थ में पूरी तरह से समतुल्य है। यह स्पष्ट रूप से दिखाता है कि हम प्रत्येक वर्ण पर जा रहे हैं।

\n\n

यह अंदर से कैसे काम करता है: std::tolower

\n\n

std::tolower फ़ंक्शन कोई जादू नहीं है। अधिकांश कार्यान्वयनों में, यह लुकअप टेबल का उपयोग करता है। unsigned char (0-255) के प्रत्येक संभावित मान के लिए, इस तालिका में लोअर केस में संबंधित मान पहले से दर्ज होता है। इस प्रकार, std::tolower('A') को कॉल करना केवल इंडेक्स 65 (वर्ण 'A' का कोड) पर ऐरे एलिमेंट तक त्वरित पहुँच है, जो 97 ('a' का कोड) लौटाएगा।

\n\n

हालाँकि, एक बारीक बात है: लोकेल। डिफ़ॉल्ट रूप से, std::tolower "C" लोकेल का उपयोग करता है, जो केवल ASCII वर्णों के साथ काम करता है। यदि आप रूसी अक्षरों, जर्मन उमलॉट्स (ä, ö, ü) या फ्रेंच उच्चारण (é, è) के साथ काम कर रहे हैं, तो क्लासिक std::tolower आपकी मदद नहीं करेगा - यह बिना किसी बदलाव के मूल वर्ण लौटा देगा।

\n\n

लोकेल की समस्या: जब एक फ़ंक्शन पर्याप्त नहीं है

\n\n

मल्टी-बाइट एन्कोडिंग और राष्ट्रीय वर्णमाला के साथ काम करने के लिए, लोकेल पैरामीटर के साथ std::tolower का उपयोग करना होगा:

\n\n
#include <locale>\n\nstd::string to_lower_cas                

ब्लॉग

पुस्तक अनुशंसाएँ