जवाबों:
स्विफ्ट 4 के लिए अपडेट किया गया
स्विफ्ट रेंज की तुलना में अधिक जटिल हैं NSRange
, और उन्हें स्विफ्ट 3 में कोई आसान नहीं मिला। यदि आप इस जटिलता के पीछे के तर्क को समझने की कोशिश करना चाहते हैं, तो इसे पढ़ें और इसे पढ़ें । मैं बस आपको दिखाऊंगा कि उन्हें कैसे बनाना है और जब आप उनका उपयोग कर सकते हैं।
a...b
यह रेंज ऑपरेटर एक स्विफ्ट रेंज बनाता है जिसमें तत्व a
और तत्व दोनों शामिल हैं b
, भले ही b
एक प्रकार (जैसे Int.max
) के लिए अधिकतम संभव मूल्य हो । दो अलग-अलग प्रकार की बंद श्रेणियां हैं: ClosedRange
और CountableClosedRange
।
ClosedRange
स्विफ्ट में सभी श्रेणियों के तत्व तुलनीय हैं (यानी, वे तुलनात्मक प्रोटोकॉल के अनुरूप हैं)। यह आपको एक संग्रह से सीमा में तत्वों का उपयोग करने की अनुमति देता है। यहाँ एक उदाहरण है:
let myRange: ClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
हालाँकि, ClosedRange
यह गणना योग्य नहीं है (यानी, यह अनुक्रम प्रोटोकॉल के अनुरूप नहीं है)। इसका मतलब है कि आप एक for
लूप के साथ तत्वों पर पुनरावृति नहीं कर सकते । उसके लिए आपको चाहिए CountableClosedRange
।
CountableClosedRange
यह पिछले एक के समान है सिवाय अब सीमा को भी पुनरावृत्त किया जा सकता है।
let myRange: CountableClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
for index in myRange {
print(myArray[index])
}
a..<b
इस रेंज ऑपरेटर में तत्व शामिल हैं, a
लेकिन तत्व नहींb
। ऊपर की तरह, दो अलग-अलग प्रकार की अर्ध-खुली सीमाएं हैं: Range
और CountableRange
।
Range
के रूप में ClosedRange
, आप एक के साथ एक संग्रह के तत्वों का उपयोग कर सकते हैं Range
। उदाहरण:
let myRange: Range = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
फिर, हालांकि, आप एक से अधिक पुनरावृति नहीं कर सकते Range
इसे क्योंकि यह केवल तुलनीय है, स् थिर नहीं है।
CountableRange
A CountableRange
पुनरावृत्ति की अनुमति देता है।
let myRange: CountableRange = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
for index in myRange {
print(myArray[index])
}
आप NSRange
स्विफ्ट ( उदाहरण के लिए जिम्मेदार स्ट्रिंग्स बनाते समय ) में अभी भी कई बार उपयोग कर सकते हैं , इसलिए यह जानना उपयोगी है कि कैसे बनाया जाए।
let myNSRange = NSRange(location: 3, length: 2)
ध्यान दें कि यह स्थान और लंबाई है , न कि अनुक्रमणिका और अंत अनुक्रमणिका। यहाँ उदाहरण स्विफ्ट रेंज के अर्थ में समान है 3..<5
। हालांकि, चूंकि प्रकार भिन्न हैं, वे विनिमेय नहीं हैं।
...
और ..<
रेंज ऑपरेटरों पर्वतमाला बनाने की एक आशुलिपि तरीका है। उदाहरण के लिए:
let myRange = 1..<3
एक ही रेंज बनाने का लंबा हाथ तरीका होगा
let myRange = CountableRange<Int>(uncheckedBounds: (lower: 1, upper: 3)) // 1..<3
आप देख सकते हैं कि यहाँ सूचकांक प्रकार है Int
। String
हालांकि, इसके लिए काम नहीं करता है , क्योंकि स्ट्रिंग्स अक्षर से बने होते हैं और सभी वर्ण समान आकार के नहीं होते हैं। (पढ़ें इस अधिक जानकारी के लिए ।) एक इमोजी जैसे info, उदाहरण के लिए, "b" अक्षर से अधिक जगह लेता है।
NSRange के साथ समस्या
साथ प्रयोग करके देखें NSRange
और एक NSString
इमोजी के साथ और आप देखेंगे कि मैं क्या मतलब है। सरदर्द।
let myNSRange = NSRange(location: 1, length: 3)
let myNSString: NSString = "abcde"
myNSString.substring(with: myNSRange) // "bcd"
let myNSString2: NSString = "a😀cde"
myNSString2.substring(with: myNSRange) // "😀c" Where is the "d"!?
स्माइली फेस स्टोर करने के लिए दो UTF-16 कोड यूनिट लेता है, इसलिए यह "d" को शामिल न करने का अप्रत्याशित परिणाम देता है।
स्विफ्ट समाधान
इस वजह से, स्विफ्ट स्ट्रिंग्स के साथ, आप उपयोग करते हैं Range<String.Index>
, नहींRange<Int>
। स्ट्रिंग इंडेक्स की गणना एक विशेष स्ट्रिंग के आधार पर की जाती है ताकि यह पता चल सके कि क्या कोई इमोजी या विस्तारित ग्रैफेम क्लस्टर हैं।
उदाहरण
var myString = "abcde"
let start = myString.index(myString.startIndex, offsetBy: 1)
let end = myString.index(myString.startIndex, offsetBy: 4)
let myRange = start..<end
myString[myRange] // "bcd"
myString = "a😀cde"
let start2 = myString.index(myString.startIndex, offsetBy: 1)
let end2 = myString.index(myString.startIndex, offsetBy: 4)
let myRange2 = start2..<end2
myString[myRange2] // "😀cd"
a...
और ...b
और..<b
स्विफ्ट में 4 चीजें थोड़ी सरल हुईं। जब भी किसी रेंज का शुरुआती या अंतिम बिंदु पता लगाया जा सकता है, तो आप इसे छोड़ सकते हैं।
इंट
आप एक-तरफा पूर्णांक श्रेणियों का उपयोग करके संग्रह से अधिक पुनरावृति कर सकते हैं। दस्तावेज से कुछ उदाहरण यहां दिए गए हैं ।
// iterate from index 2 to the end of the array
for name in names[2...] {
print(name)
}
// iterate from the beginning of the array to index 2
for name in names[...2] {
print(name)
}
// iterate from the beginning of the array up to but not including index 2
for name in names[..<2] {
print(name)
}
// the range from negative infinity to 5. You can't iterate forward
// over this because the starting point in unknown.
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
// You can iterate over this but it will be an infinate loop
// so you have to break out at some point.
let range = 5...
तार
यह स्ट्रिंग रेंज के साथ भी काम करता है। यदि आप एक सीमा के साथ str.startIndex
या str.endIndex
एक छोर पर बना रहे हैं , तो आप इसे छोड़ सकते हैं। संकलक इसे अनुमान लगाएगा।
दिया हुआ
var str = "Hello, playground"
let index = str.index(str.startIndex, offsetBy: 5)
let myRange = ..<index // Hello
आप इंडेक्स से str.endIndex पर जाकर उपयोग कर सकते हैं ...
var str = "Hello, playground"
let index = str.index(str.endIndex, offsetBy: -10)
let myRange = index... // playground
टिप्पणियाँ
NSString
आंतरिक रूप से अपने पात्रों को UTF-16 एन्कोडिंग में संग्रहीत करता है। एक पूर्ण यूनिकोड स्केलर 21-बिट है। ग्रिनिंग फेस कैरेक्टर ( U+1F600
) को 16-बिट कोड यूनिट में संग्रहित नहीं किया जा सकता है, इसलिए यह 2. NSRange
बिट कोड यूनिट्स के आधार पर 2. काउंट्स में फैला हुआ है । इस उदाहरण में, 3 कोड इकाइयां केवल 2 वर्णों का प्रतिनिधित्व करने के लिए होती हैं
Xcode 8 बीटा 2 • स्विफ्ट 3
let myString = "Hello World"
let myRange = myString.startIndex..<myString.index(myString.startIndex, offsetBy: 5)
let mySubString = myString.substring(with: myRange) // Hello
Xcode 7 • स्विफ्ट 2.0
let myString = "Hello World"
let myRange = Range<String.Index>(start: myString.startIndex, end: myString.startIndex.advancedBy(5))
let mySubString = myString.substringWithRange(myRange) // Hello
या केवल
let myString = "Hello World"
let myRange = myString.startIndex..<myString.startIndex.advancedBy(5)
let mySubString = myString.substringWithRange(myRange) // Hello
इस तरह का उपयोग करें
var start = str.startIndex // Start at the string's start index
var end = advance(str.startIndex, 5) // Take start index and advance 5 characters forward
var range: Range<String.Index> = Range<String.Index>(start: start,end: end)
let firstFiveDigit = str.substringWithRange(range)
print(firstFiveDigit)
आउटपुट: नमस्कार
मुझे यह आश्चर्यजनक लगता है कि, स्विफ्ट 4 में भी, इंट का उपयोग करके स्ट्रिंग रेंज को व्यक्त करने का कोई सरल देशी तरीका नहीं है। एकमात्र स्ट्रिंग विधियाँ जो आपको एक Int सप्लाई करती हैं जैसे कि रेंज द्वारा एक सबरिंग प्राप्त करने का एक तरीका है prefix
और suffix
।
कुछ रूपांतरण उपयोगिताओं को हाथ में लेना उपयोगी है, ताकि हम स्ट्रिंग की बात करते समय NSRange की तरह बात कर सकें। यहां एक उपयोगिता है जो NSRange की तरह ही एक स्थान और लंबाई लेता है, और एक रिटर्न देता है Range<String.Index>
:
func range(_ start:Int, _ length:Int) -> Range<String.Index> {
let i = self.index(start >= 0 ? self.startIndex : self.endIndex,
offsetBy: start)
let j = self.index(i, offsetBy: length)
return i..<j
}
उदाहरण के लिए, "hello".range(0,1)"
है Range<String.Index>
का पहला वर्ण को गले लगाने "hello"
। एक बोनस के रूप में, मैं नकारात्मक स्थान की अनुमति दी है: "hello".range(-1,1)"
है Range<String.Index>
का अंतिम वर्ण को गले लगाने "hello"
।
यह Range<String.Index>
एक NSRange में परिवर्तित करने के लिए भी उपयोगी है , उन क्षणों के लिए जब आपको कोको से बात करनी है (उदाहरण के लिए, NSAttributedString विशेषता श्रेणियों से निपटने में)। स्विफ्ट 4 ऐसा करने का मूल तरीका प्रदान करता है:
let nsrange = NSRange(range, in:s) // where s is the string
इस प्रकार हम एक और उपयोगिता लिख सकते हैं जहाँ हम सीधे स्ट्रिंग लोकेशन और लंबाई से NSRange तक जाते हैं:
extension String {
func nsRange(_ start:Int, _ length:Int) -> NSRange {
return NSRange(self.range(start,length), in:self)
}
}
मैंने निम्नलिखित एक्सटेंशन बनाया:
extension String {
func substring(from from:Int, to:Int) -> String? {
if from<to && from>=0 && to<self.characters.count {
let rng = self.startIndex.advancedBy(from)..<self.startIndex.advancedBy(to)
return self.substringWithRange(rng)
} else {
return nil
}
}
}
उपयोग का उदाहरण:
print("abcde".substring(from: 1, to: 10)) //nil
print("abcde".substring(from: 2, to: 4)) //Optional("cd")
print("abcde".substring(from: 1, to: 0)) //nil
print("abcde".substring(from: 1, to: 1)) //nil
print("abcde".substring(from: -1, to: 1)) //nil
आप इस तरह का उपयोग कर सकते हैं
let nsRange = NSRange(location: someInt, length: someInt)
जैसे की
let myNSString = bigTOTPCode as NSString //12345678
let firstDigit = myNSString.substringWithRange(NSRange(location: 0, length: 1)) //1
let secondDigit = myNSString.substringWithRange(NSRange(location: 1, length: 1)) //2
let thirdDigit = myNSString.substringWithRange(NSRange(location: 2, length: 4)) //3456
मैं यह करना चाहता हूँ:
print("Hello"[1...3])
// out: Error
लेकिन दुर्भाग्य से, मैं अपनी खुद की एक उप-प्रलेख नहीं लिख सकता, क्योंकि शिथिल व्यक्ति नाम स्थान लेता है।
हम हालांकि यह कर सकते हैं:
print("Hello"[range: 1...3])
// out: ell
बस इसे अपने प्रोजेक्ट में जोड़ें:
extension String {
subscript(range: ClosedRange<Int>) -> String {
get {
let start = String.Index(utf16Offset: range.lowerBound, in: self)
let end = String.Index(utf16Offset: range.upperBound, in: self)
return String(self[start...end])
}
}
}
Range<String.Index>
, लेकिन कभी-कभी इसके साथ काम करना आवश्यक होता हैNSString
औरNSRange
इसलिए कुछ और संदर्भ उपयोगी होंगे। - लेकिन stackoverflow.com/questions/24092884/… पर एक नज़र डालें ।