swift - स्विफ्ट में स्ट्रिंग स्ट्रिंग कैसे काम करती है




string range (11)

स्विफ्ट 4

स्विफ्ट में 4 String Collection अनुरूप है। substring करने के बजाय, हमें अब एक subscript. उपयोग करना चाहिए subscript. इसलिए यदि आप "Hello, playground" से केवल "play" शब्द को काटना चाहते हैं, तो आप इसे इस तरह से कर सकते हैं:

var str = "Hello, playground"
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let result = str[start..<end] // The result is of type Substring

यह जानना दिलचस्प है, कि ऐसा करने से आपको एक String बजाय एक विकल्प मिलेगा। यह तेज और कुशल है क्योंकि मूल स्ट्रिंग के साथ Substring अपने स्टोरेज को साझा करता है। हालाँकि इस तरह से मेमोरी शेयर करने से मेमोरी लीक भी आसानी से हो सकती है।

यही कारण है कि आपको मूल स्ट्रिंग को साफ करने के लिए एक बार, परिणाम को एक नए स्ट्रिंग में कॉपी करना चाहिए। आप सामान्य कंस्ट्रक्टर का उपयोग करके ऐसा कर सकते हैं:

let newString = String(result)

आप [Apple दस्तावेज़ीकरण] में नए Substring वर्ग के बारे में अधिक जानकारी पा सकते हैं। 1

इसलिए, यदि आप उदाहरण के लिए NSRegularExpression के परिणाम के रूप में एक Range प्राप्त करते हैं, तो आप निम्नलिखित एक्सटेंशन का उपयोग कर सकते हैं:

extension String {

    subscript(_ range: NSRange) -> String {
        let start = self.index(self.startIndex, offsetBy: range.lowerBound)
        let end = self.index(self.startIndex, offsetBy: range.upperBound)
        let subString = self[start..<end]
        return String(subString)
    }

}

मैं स्विफ्ट 3 के साथ अपने पुराने कोड और उत्तरों में से कुछ को अपडेट कर रहा हूं, लेकिन जब मैं स्विफ्ट स्ट्रिंग्स और इंडेक्सिंग के साथ सबस्टिट्यूटिंग चीजों को भ्रमित कर रहा हूं।

विशेष रूप से मैं निम्नलिखित कोशिश कर रहा था:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

जहाँ दूसरी पंक्ति मुझे निम्नलिखित त्रुटि दे रही थी

मूल्य का प्रकार 'स्ट्रिंग' में कोई सदस्य नहीं है 'substringWithRange'

मैं देखता हूं कि String अब निम्नलिखित तरीके हैं:

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

ये वास्तव में पहली बार मुझे भ्रमित कर रहे थे इसलिए मैंने सूचकांक और सीमा के आसपास खेलना शुरू कर दिया। यह एक अनुवर्ती प्रश्न है और प्रतिस्थापन के लिए उत्तर है। मैं नीचे एक उत्तर जोड़ रहा हूं कि वे कैसे उपयोग किए जाते हैं।


ऊपर की ओर निर्माण मुझे गैर-मुद्रण चरित्र को छोड़ने वाले गैर-मुद्रण वर्ण पर एक स्ट्रिंग को विभाजित करने की आवश्यकता थी। मैंने दो तरीके विकसित किए:

let greeting = "Hi there! It's nice to meet you! 👋"
let endOfSentence = greeting.index(of: "!")!
let firstSentence = greeting[...endOfSentence]
// firstSentence == "Hi there!"

जो मैंने ऊपर के कुछ उत्तरों का उपयोग करके एक साथ रखा।

क्योंकि एक स्ट्रिंग एक संग्रह है जो मैंने तब किया था:

private typealias HowDoYouLikeThatElonMusk = String
private extension HowDoYouLikeThatElonMusk {

    subscript(_ from: Character?, _ to: Character?, _ include: Bool) -> String? {
        if let _from: Character = from, let _to: Character = to {
            let dynamicSourceForEnd: String = (_from == _to ? String(self.reversed()) : self)
            guard let startOfSentence: String.Index = self.index(of: _from),
                let endOfSentence: String.Index = dynamicSourceForEnd.index(of: _to) else {
                return nil
            }

            let result: String = String(self[startOfSentence...endOfSentence])
            if include == false {
                guard result.count > 2 else {
                        return nil
                }
                return String(result[result.index(result.startIndex, offsetBy: 1)..<result.index(result.endIndex, offsetBy: -1)])
            }
            return result
        } else if let _from: Character = from {
            guard let startOfSentence: String.Index = self.index(of: _from) else {
                return nil
            }
            let result: String = String(self[startOfSentence...])
            if include == false {
                guard result.count > 1 else {
                    return nil
                }
                return String(result[result.index(result.startIndex, offsetBy: 1)...])
            }
            return result
        } else if let _to: Character = to {
            guard let endOfSentence: String.Index = self.index(of: _to) else {
                    return nil
            }
            let result: String = String(self[...endOfSentence])
            if include == false {
                guard result.count > 1 else {
                    return nil
                }
                return String(result[..<result.index(result.endIndex, offsetBy: -1)])
            }
            return result
        }
        return nil
    }
}

जो मेरे लिए अधिक सहज था। कौन सा सबसे अच्छा है? मेरे पास यह बताने का कोई तरीका नहीं है कि वे दोनों स्विफ्ट 5 के साथ काम करते हैं


मेरी वही शुरुआती प्रतिक्रिया थी। मुझे इस बात पर भी निराशा हुई कि हर बड़ी रिलीज़ में सिंटैक्स और ऑब्जेक्ट्स में कितना बदलाव आता है।

हालांकि, मुझे अनुभव से एहसास हुआ कि मैं हमेशा "बदलाव" से लड़ने की कोशिश करने के परिणामों को कैसे भुगतता हूं जैसे कि मल्टी-बाइट पात्रों से निपटना जो कि अगर आप वैश्विक दर्शकों को देख रहे हैं तो अपरिहार्य है।

इसलिए मैंने Apple इंजीनियरों द्वारा लगाए गए प्रयासों को पहचानने और उनका सम्मान करने का फैसला किया और इस "भयावह" दृष्टिकोण के साथ आने पर उनकी मानसिकता को समझने के लिए मेरी ओर से किया।

एक्सटेंशन बनाने के बजाय जो आपके जीवन को आसान बनाने के लिए सिर्फ एक समाधान है (मैं कह रहा हूं कि वे गलत या महंगे नहीं हैं), यह पता नहीं क्यों स्ट्रिंग्स को अब काम करने के लिए डिज़ाइन किया गया है।

उदाहरण के लिए, मेरे पास यह कोड था जो स्विफ्ट 2.2 पर काम कर रहा था:

let rString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let gString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let bString = String(cString.characters.prefix(2))

और सबस्ट्रिंग का उपयोग करते हुए काम करने के लिए एक ही दृष्टिकोण प्राप्त करने की कोशिश करने के बाद, मैंने आखिरकार स्ट्रिंग्स को एक द्विदिश संग्रह के रूप में मानने की अवधारणा को समझा, जिसके लिए मैंने एक ही कोड के इस संस्करण के साथ समाप्त किया:

func substring(string: String, fromIndex: Int, toIndex: Int) -> String? {
    if fromIndex < toIndex && toIndex < string.count /*use string.characters.count for swift3*/{
        let startIndex = string.index(string.startIndex, offsetBy: fromIndex)
        let endIndex = string.index(string.startIndex, offsetBy: toIndex)
        return String(string[startIndex..<endIndex])
    }else{
        return nil
    }
}

मुझे आशा है कि यह योगदान देता है ...


मैं काफी मैकेनिकल सोच वाला हूं। यहां मूल बातें हैं ...

स्विफ्ट 4 स्विफ्ट 5

var fString = String()
for (n,c) in str.enumerated(){

*if c == "\u{1A}" {
    print(fString);
    let lString = str.dropFirst(n + 1)
    print(lString)
    break
   }
 fString += String(c)
}*

परिणाम एक विकल्प है, जिसका अर्थ है कि यह मूल स्ट्रिंग का एक हिस्सा है। एक पूर्ण विकसित अलग स्ट्रिंग प्राप्त करने के लिए उदाहरण के लिए उपयोग करें

  let t = "abracadabra"

  let start1 = t.index(t.startIndex, offsetBy:0)
  let   end1 = t.index(t.endIndex, offsetBy:-5)
  let start2 = t.index(t.endIndex, offsetBy:-5)
  let   end2 = t.index(t.endIndex, offsetBy:0)

  let t2 = t[start1 ..< end1]
  let t3 = t[start2 ..< end2]                

  //or a shorter form 

  let t4 = t[..<end1]
  let t5 = t[start2...]

  print("\(t2) \(t3) \(t)")
  print("\(t4) \(t5) \(t)")

  // result:
  // abraca dabra abracadabra

यही है वह जो मेरे द्वारा उपयोग किया जाता है:

    String(t3)
    String(t4)

मैं स्विफ्ट के स्ट्रिंग एक्सेस मॉडल पर वास्तव में निराश हूं: सब कुछ एक Index होना चाहिए। मैं चाहता हूं कि Int का उपयोग करके स्ट्रिंग के i-वें चरित्र तक पहुंच हो, न कि अनाड़ी सूचकांक और अग्रिम (जो हर बड़ी रिलीज के साथ बदलने के लिए होता है)। इसलिए मैंने String विस्तार किया:

extension String {
    func index(from: Int) -> Index {
        return self.index(startIndex, offsetBy: from)
    }

    func substring(from: Int) -> String {
        let fromIndex = index(from: from)
        return substring(from: fromIndex)
    }

    func substring(to: Int) -> String {
        let toIndex = index(from: to)
        return substring(to: toIndex)
    }

    func substring(with r: Range<Int>) -> String {
        let startIndex = index(from: r.lowerBound)
        let endIndex = index(from: r.upperBound)
        return substring(with: startIndex..<endIndex)
    }
}

let str = "Hello, playground"
print(str.substring(from: 7))         // playground
print(str.substring(to: 5))           // Hello
print(str.substring(with: 7..<11))    // play

मैंने इसके लिए एक सरल एक्सटेंशन बनाया (स्विफ्ट 3)

    let mid = t.index(t.endIndex, offsetBy:-5)
    let firstHalf = t[..<mid]
    let secondHalf = t[mid...]

स्विफ्ट 4

"पदार्थ" ( 1 )

let source =                                   ">>>01234..56789<<<"
// include = true
var from =          source["3", nil, true]  //       "34..56789<<<"
var to =            source[nil, "6", true]  // ">>>01234..56"
var fromTo =        source["3", "6", true]  //       "34..56"
let notFound =      source["a", nil, true]  // nil
// include = false
from =              source["3", nil, false] //        "4..56789<<<"
to =                source[nil, "6", false] // ">>>01234..5"
fromTo =            source["3", "6", false] //        "4..5"
let outOfBounds =   source[".", ".", false] // nil

let str = "Hello, playground"
let hello = str[nil, ",", false] // "Hello"

विस्तार स्ट्रिंग का उदाहरण:

extension String
{
    func subString <R> (_ range: R) -> String? where R : RangeExpression, String.Index == R.Bound
    {
        return String(self[range])
    }

    func index(at: Int) -> Index
    {
        return self.index(self.startIndex, offsetBy: at)
    }
}

एक्सटेंशन स्ट्रिंग का उपयोग करने का उदाहरण:

let item = "Fred looks funny"
item.subString(item.index(at: 2)...) // "ed looks funny"

स्विफ्ट 4 एक्सटेंशन:

extension String { 
    subscript(_ range: CountableRange<Int>) -> String { 
        let idx1 = index(startIndex, offsetBy: max(0, range.lowerBound))
        let idx2 = index(startIndex, offsetBy: min(self.count, range.upperBound))
        return String(self[idx1..<idx2])
    }    
}       

उपयोग:

let s = "hello"
s[0..<3] // "hel"
s[3..<s.count] // "lo"

या यूनिकोड:

let s = "😎🤣😋"
s[0..<1] // "😎"

एक अधिक सामान्य कार्यान्वयन का उपयोग करता है:

यह तकनीक अभी भी स्विफ्ट के मानकों को ध्यान में रखने के लिए index का उपयोग करती है, और एक पूर्ण चरित्र को लागू करती है।

extension String {
    func take(_ n: Int) -> String {
        guard n >= 0 else {
            fatalError("n should never negative")
        }
        let index = self.index(self.startIndex, offsetBy: min(n, self.count))
        return String(self[..<index])
    }
}

तीसरे वर्ण से उप स्ट्रिंग करने के लिए:

let text = "Hello, World!"
let substring = text.take(5) //Hello

मैंने ऊंट subString String उपयोग करने के लिए यह इंगित करने के लिए उपयोग किया है कि यह String और subString नहीं है।


स्विफ्ट 4

var str = "abc\u{1A}12345sdf"
let range1: Range<String.Index> = str.range(of: "\u{1A}")!
let index1: Int = str.distance(from: str.startIndex, to: range1.lowerBound)
let start = str.index(str.startIndex, offsetBy: index1)
let end = str.index(str.endIndex, offsetBy: -0)
let result = str[start..<end] // The result is of type Substring
let firstStr = str[str.startIndex..<range1.lowerBound]

स्विफ्ट 4+

extension String {
    subscript(_ i: Int) -> String {
        let idx1 = index(startIndex, offsetBy: i)
        let idx2 = index(idx1, offsetBy: 1)
        return String(self[idx1..<idx2])
    }
}

let s = "hello"

s[0]    // h
s[1]    // e
s[2]    // l
s[3]    // l
s[4]    // o

यदि स्ट्रिंग छोटा है, तो पहले n वर्णों की संपूर्णता या संपूर्ण स्ट्रिंग लौटाता है। (इससे प्रेरित: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html )

उदाहरण:

extension String {
    func substring(location: Int, length: Int) -> String? {
        guard characters.count >= location + length else { return nil }
        let start = index(startIndex, offsetBy: location)
        let end = index(startIndex, offsetBy: location + length)
        return substring(with: start..<end)
    }
}





substring