यह String
स्विफ्ट कैसे काम करता है, और contains(_:)
विधि कैसे काम करती है, इसके साथ क्या करना है ।
The 'known'👧👧👦👦 ’एक इमोजी अनुक्रम के रूप में जाना जाता है, जिसे एक स्ट्रिंग में एक दृश्यमान चरित्र के रूप में प्रस्तुत किया गया है। अनुक्रम Character
वस्तुओं से बना है , और साथ ही यह UnicodeScalar
वस्तुओं से बना है ।
यदि आप स्ट्रिंग के कैरेक्टर काउंट की जाँच करते हैं, तो आप देखेंगे कि यह चार अक्षरों से बना है, जबकि यदि आप यूनिकोड स्केलर काउंट की जाँच करते हैं, तो यह आपको एक अलग परिणाम दिखाएगा:
print("👩👩👧👦".characters.count) // 4
print("👩👩👧👦".unicodeScalars.count) // 7
अब, यदि आप वर्णों के माध्यम से पार्स करते हैं और उन्हें प्रिंट करते हैं, तो आप देखेंगे कि सामान्य पात्रों की तरह क्या लगता है, लेकिन वास्तव में तीन पहले पात्रों में एक इमोजी और साथ ही साथ एक शून्य-चौड़ाई वाले योजक शामिल हैं UnicodeScalarView
:
for char in "👩👩👧👦".characters {
print(char)
let scalars = String(char).unicodeScalars.map({ String($0.value, radix: 16) })
print(scalars)
}
// 👩
// ["1f469", "200d"]
// 👩
// ["1f469", "200d"]
// 👧
// ["1f467", "200d"]
// 👦
// ["1f466"]
जैसा कि आप देख सकते हैं, केवल अंतिम वर्ण में शून्य-चौड़ाई वाला योजक शामिल नहीं है, इसलिए contains(_:)
विधि का उपयोग करते समय , यह आपकी अपेक्षा के अनुरूप काम करता है। चूंकि आप शून्य-चौड़ाई वाले जॉइनरों वाले इमोजी के खिलाफ तुलना नहीं कर रहे हैं, इसलिए विधि किसी भी अंतिम वर्ण के लिए मैच नहीं ढूंढेगी।
इस पर विस्तार करने के लिए, यदि आप एक String
ऐसा बनाते हैं जो शून्य-चौड़ाई वाले योजक के साथ समाप्त होने वाले इमोजी चरित्र से बना होता है, और इसे contains(_:)
विधि में पास करता है , तो यह भी मूल्यांकन करेगा false
। इसका contains(_:)
ठीक उसी प्रकार से होना है range(of:) != nil
, जैसा कि दिए गए तर्क का सटीक मिलान खोजने की कोशिश करता है। चूंकि शून्य-चौड़ाई वाले योजक के साथ समाप्त होने वाले वर्ण एक अपूर्ण अनुक्रम बनाते हैं, इसलिए विधि एक पूर्ण-अनुक्रम में शून्य-चौड़ाई वाले योजक के साथ समाप्त होने वाले वर्णों को मिलाते हुए तर्क के लिए एक मैच खोजने की कोशिश करती है। इसका मतलब है कि विधि कभी भी एक मैच नहीं ढूंढेगी यदि:
- तर्क शून्य-चौड़ाई वाले योजक के साथ समाप्त होता है, और
- पार्स करने के लिए स्ट्रिंग में एक अधूरा अनुक्रम नहीं होता है (यानी एक शून्य-चौड़ाई वाले योजक के साथ समाप्त होता है और एक संगत चरित्र द्वारा पीछा नहीं किया जाता है)।
प्रदर्शित करना:
let s = "\u{1f469}\u{200d}\u{1f469}\u{200d}\u{1f467}\u{200d}\u{1f466}" // 👩👩👧👦
s.range(of: "\u{1f469}\u{200d}") != nil // false
s.range(of: "\u{1f469}\u{200d}\u{1f469}") != nil // false
हालाँकि, चूंकि तुलना केवल आगे की है, आप पीछे की ओर काम करके स्ट्रिंग के भीतर कई अन्य पूर्ण अनुक्रम पा सकते हैं:
s.range(of: "\u{1f466}") != nil // true
s.range(of: "\u{1f467}\u{200d}\u{1f466}") != nil // true
s.range(of: "\u{1f469}\u{200d}\u{1f467}\u{200d}\u{1f466}") != nil // true
// Same as the above:
s.contains("\u{1f469}\u{200d}\u{1f467}\u{200d}\u{1f466}") // true
सबसे आसान समाधान range(of:options:range:locale:)
विधि के लिए एक विशिष्ट तुलना विकल्प प्रदान करना होगा । विकल्प String.CompareOptions.literal
एक सटीक चरित्र-दर-वर्ण समानता पर तुलना करता है । एक साइड नोट के रूप में, यहां चरित्र का क्या मतलब है , स्विफ्ट नहीं है Character
, लेकिन यूटीएफ -16 दोनों उदाहरण और तुलना स्ट्रिंग का प्रतिनिधित्व करते हैं - हालांकि, चूंकि String
विकृत यूटीएफ -16 अनुमति नहीं देता है, यह अनिवार्य रूप से यूनिकोड स्केलर की तुलना करने के बराबर है। प्रतिनिधित्व।
यहाँ मैंने Foundation
विधि को ओवरलोड किया है, इसलिए यदि आपको मूल एक की आवश्यकता है, तो इस एक या कुछ का नाम बदलें:
extension String {
func contains(_ string: String) -> Bool {
return self.range(of: string, options: String.CompareOptions.literal) != nil
}
}
अब यह विधि अधूरे क्रमों के साथ भी प्रत्येक वर्ण के साथ "होनी चाहिए":
s.contains("👩") // true
s.contains("👩\u{200d}") // true
s.contains("\u{200d}") // true