परिचय: "स्ट्रिंग की लंबाई" सिर्फ एक संख्या क्यों नहीं है?
\n\nकल्पना करें कि आप iOS के लिए एक ऐप लिख रहे हैं। उपयोगकर्ता टेक्स्ट फ़ील्ड में अपना नाम दर्ज करता है। सब कुछ सरल है? लेकिन क्या होगा अगर नाम में इमोजी, विशेषक चिह्न (जैसे, "café") या चित्रलिपि हों? अचानक "स्ट्रिंग की लंबाई प्राप्त करने" का सरल कार्य Unicode तत्वों के साथ एक जासूसी कहानी में बदल जाता है।
\n\nSwift में स्ट्रिंग्स के साथ काम करना सिर्फ वर्णों की गिनती नहीं है। यह ग्राफेम क्लस्टर, Unicode-स्केलर और Objective-C की विरासत (हाँ, NSString अभी भी हमारे साथ है) की दुनिया की यात्रा है। यदि आप अभी Swift सीखना शुरू कर रहे हैं या अन्य भाषाओं से आ रहे हैं, तो यह लेख आपके लिए है। हम समझेंगे कि स्ट्रिंग की लंबाई सही तरीके से कैसे निर्धारित करें, कौन सी छिपी समस्याएं आपका इंतजार कर रही हैं, और कब count का उपयोग करना है और कब NSString का।
यह सामग्री Stack Overflow के एक वास्तविक लोकप्रिय प्रश्न पर आधारित है। हजारों डेवलपर्स इस विषय पर फिसले हैं। आइए हम उनकी गलतियों को न दोहराएं। चलिए शुरू करते हैं!
\n\n\n\n
1. मूल बातें: String का count गुण
\n\nSwift में स्ट्रिंग की लंबाई प्राप्त करने का सबसे स्पष्ट तरीका count गुण का उपयोग करना है। यह स्ट्रिंग में "वर्णों" (Character) की संख्या लौटाता है। लेकिन Swift के लिए वर्ण क्या है?
let greeting = "Привет, мир!"\nprint(greeting.count) // 12 (स्पेस और विस्मयादिबोधक चिह्न सहित)\n\nसब कुछ अपेक्षित रूप से काम करता है। लेकिन आइए कार्य को जटिल बनाते हैं:
\n\nlet emojiString = "👨👩👧👦"\nprint(emojiString.count) // 1 (!!!)\n\nएक? सच में? जबकि देखने में यह चार लोगों का पूरा परिवार है। क्या चाल है?
\n\nइसका उत्तर इस बात में छिपा है कि Swift स्ट्रिंग्स को कैसे संसाधित करता है। count बाइट्स या अलग-अलग Unicode वर्णों की गिनती नहीं करता, बल्कि विस्तारित ग्राफेम क्लस्टर (extended grapheme clusters) की गिनती करता है। यह एक या अधिक Unicode-स्केलर का अनुक्रम है जिसे उपयोगकर्ता एक ही वर्ण के रूप में देखता है। इमोजी "परिवार" कई भागों से बना है, लेकिन Swift इसे एक ही वर्ण मानता है, क्योंकि इंसान इसे ऐसे ही देखता है।
यह व्यवहार कोई बग नहीं, बल्कि एक फीचर है। Swift को अंतर्राष्ट्रीयकरण को ध्यान में रखकर डिज़ाइन किया गया है। यदि count प्रत्येक Unicode-स्केलर की गिनती करता, तो स्ट्रिंग "café" (एक वर्ण é के साथ) अलग-अलग परिणाम दे सकती थी, यह इस बात पर निर्भर करता कि é कैसे एन्कोड किया गया है: एकल वर्ण U+00E9 के रूप में या e + उच्चारण (U+0065 + U+0301) के संयोजन के रूप में।
let cafe1 = "café" // é एकल वर्ण के रूप में\nlet cafe2 = "cafe\\u{0301}" // e + उच्चारण\nprint(cafe1.count) // 4\nprint(cafe2.count) // 4 (हालांकि स्ट्रिंग में 5 स्केलर हैं)\n\nSwift दोनों विकल्पों को 4 वर्ण मानता है, क्योंकि उपयोगकर्ता 4 अक्षरों का "café" देखता है। यही ग्राफेम क्लस्टर का जादू है।
\n\n\n\n
2. वैकल्पिक दृष्टिकोण: NSString और length गुण
\n\nकभी-कभी आपको "मानवीय" वर्णों की संख्या नहीं, बल्कि UTF-16 एन्कोडिंग इकाइयों की संख्या प्राप्त करने की आवश्यकता होती है। उदाहरण के लिए, पुराने API, Core Text के साथ काम करते समय, या उन प्रारूपों में डेटा स्थानांतरित करते समय जो UTF-16 में लंबाई की अपेक्षा करते हैं (जैसे कुछ नेटवर्क प्रोटोकॉल)।
\n\nयहाँ NSString मदद करता है - Objective-C का पुराना अच्छा क्लास। Swift स्ट्रिंग्स स्वचालित रूप से NSString में ब्रिज (bridge) हो जाती हैं, इसलिए आप इसके length गुण का उपयोग कर सकते हैं:
let swiftString = "👨👩👧👦"\nlet nsString = swiftString as NSString\nprint(nsString.length) // 11 (UTF-16 इकाइयों की संख्या)\n\n11 क्यों? क्योंकि यौगिक इमोजी "परिवार" UTF-16 में 11 इकाइयाँ लेता है (प्रत्येक घटक सरोगेट जोड़ी या अलग वर्ण के रूप में एन्कोड होता है)। यदि आप उस टेक्स्ट के साथ काम कर रहे हैं जिसे पुरानी C-लाइब्रेरी या API द्वारा संसाधित किया जाएगा जो NSString की अपेक्षा करते हैं, तो length का उपयोग करें। लेकिन याद रखें: यह उपयोगकर्ता द्वारा देखे जाने वाले वर्णों की संख्या नहीं है।
एक और बारीक बात: NSString ग्राफेम क्लस्टर पर विचार नहीं करता। स्ट्रिंग "café" (दूसरे विकल्प) के लिए, length 5 लौटाएगा, जबकि count 4 लौटाता है। निष्कर्ष: विधि चुनें