स्विफ्ट में "Int" टाइप करने के लिए "इंडेक्स" कैसे बदलें?


89

मैं एक स्ट्रिंग के भीतर निहित पत्र के सूचकांक को पूर्णांक मान में परिवर्तित करना चाहता हूं। शीर्ष लेख फ़ाइलों को पढ़ने का प्रयास किया गया, लेकिन मैं इसके लिए प्रकार नहीं ढूँढ सकता Index, हालांकि यह ForwardIndexTypeविधियों (जैसे distanceTo) के साथ प्रोटोकॉल के अनुरूप प्रतीत होता है ।

var letters = "abcdefg"
let index = letters.characters.indexOf("c")!

// ERROR: Cannot invoke initializer for type 'Int' with an argument list of type '(String.CharacterView.Index)'
let intValue = Int(index)  // I want the integer value of the index (e.g. 2)

किसी भी मदद की सराहना की है।


क्या आपके पास xcode 7.2 और स्विफ्ट 2.x है?
अनसैतेव

वास्तव में, मैं इस समय Xcode 7.2 सही डाउनलोड कर रहा हूं।
क्रिस्टोफर

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

1
स्विफ्ट 3: let index = letters.characters.index(of: "c") अगली पंक्तिlet int_index = letters.characters.distance(from: letters.startIndex, to: index)
विक्टर

8
Apple WTF !!!!!!
बोरहज

जवाबों:


87

संपादित करें / अद्यतन:

Xcode 11 • स्विफ्ट 5.1 या बाद में

extension StringProtocol {
    func distance(of element: Element) -> Int? { firstIndex(of: element)?.distance(in: self) }
    func distance<S: StringProtocol>(of string: S) -> Int? { range(of: string)?.lowerBound.distance(in: self) }
}

extension Collection {
    func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
}

extension String.Index {
    func distance<S: StringProtocol>(in string: S) -> Int { string.distance(to: self) }
}

खेल का मैदान परीक्षण

let letters = "abcdefg"

let char: Character = "c"
if let distance = letters.distance(of: char) {
    print("character \(char) was found at position #\(distance)")   // "character c was found at position #2\n"
} else {
    print("character \(char) was not found")
}

let string = "cde"
if let distance = letters.distance(of: string) {
    print("string \(string) was found at position #\(distance)")   // "string cde was found at position #2\n"
} else {
    print("string \(string) was not found")
}

47
मैं बहुत उलझन में हूं कि वे सिर्फ एक फ़ंक्शन बनाने का फैसला क्यों नहीं करेंगे जो किसी सरणी तत्व के पूर्णांक-मूल्य सूचकांक को वापस करता है .. smh
MarksCode

6
सभी पात्रों को एक बाइट में संग्रहीत नहीं किया जा सकता है। आपको कुछ समय लेना चाहिए और स्विफ्ट स्ट्रिंग दस्तावेज
लियो डबस


4
Tbh मैं एक नियमित सरणी के तत्व का पूर्णांक-मूल्य सूचकांक प्राप्त करने की कोशिश कर रहा हूं, न कि एक स्ट्रिंग।
मार्कसकोड

28
साधारण चीजें बनाना अनावश्यक रूप से जटिल :(
युलिआन Onofrei

4

स्विफ्ट 4

var str = "abcdefg"
let index = str.index(of: "c")?.encodedOffset // Result: 2

नोट: यदि स्ट्रिंग में एक से अधिक वर्ण हैं, तो यह बस बाईं ओर से निकटतम प्राप्त करेगा

var str = "abcdefgc"
let index = str.index(of: "c")?.encodedOffset // Result: 2

5
एन्कोडेडऑफ़सेट का उपयोग न करें। एन्कोडेडऑफ़सेट को हटा दिया गया है: एन्कोडेडऑफ़सेट को हटा दिया गया है क्योंकि अधिकांश आम उपयोग गलत है। कोशिश करें"🇺🇸🇺🇸🇧🇷".index(of: "🇧🇷")?.encodedOffset // 16
लियो डबस

@LeoDabus आप सही ढंग से बता रहे हैं कि यह पदावनत है। लेकिन आप इसे उत्तर के रूप में उपयोग करने का सुझाव दे रहे हैं। सही उत्तर है: index_Of_YourStringVariable.utf16Offset (in: yourStringVariable)
TDesign

नहीं UTF16 ऑफसेट यह संभवत: वह नहीं है जो आप चाहते हैं
लियो डबस

1

encodedOffsetस्विफ्ट 4.2 से हटा दिया गया है ।

पदावनति संदेश: encodedOffsetअधिकांश सामान्य उपयोग गलत होने के कारण पदावनत कर दिया गया है। utf16Offset(in:)उसी व्यवहार को प्राप्त करने के लिए उपयोग करें ।

तो हम utf16Offset(in:)इस तरह का उपयोग कर सकते हैं :

var str = "abcdefgc"
let index = str.index(of: "c")?.utf16Offset(in: str) // Result: 2

1
कोशिश let str = "🇺🇸🇺🇸🇧🇷" let index = str.firstIndex(of: "🇧🇷")?.utf16Offset(in: str)// परिणाम: 8
लियो डबस

0

सूचकांक के आधार पर स्ट्रिंग ऑपरेशन करने के लिए, आप इसे पारंपरिक सूचकांक संख्यात्मक दृष्टिकोण के साथ नहीं कर सकते। क्योंकि स्विफ्ट .index इंडेक्स फ़ंक्शन द्वारा पुनर्प्राप्त किया जाता है और यह इंट प्रकार में नहीं है। हालांकि स्ट्रिंग वर्णों की एक सरणी है, फिर भी हम सूचकांक द्वारा तत्व नहीं पढ़ सकते हैं।

यह निराश करने वाला है।

इसलिए, स्ट्रिंग के हर वर्ण के नए विकल्प बनाने के लिए, नीचे दिए गए कोड की जाँच करें।

let mystr = "abcdefghijklmnopqrstuvwxyz"
let mystrArray = Array(mystr)
let strLength = mystrArray.count
var resultStrArray : [Character] = []
var i = 0
while i < strLength {
    if i % 2 == 0 {
        resultStrArray.append(mystrArray[i])
      }
    i += 1
}
let resultString = String(resultStrArray)
print(resultString)

आउटपुट: acegikmoqsuwy

अग्रिम में धन्यवाद


इसे आसानी से फ़िल्टर के साथ पूरा किया जा सकता हैvar counter = 0 let result = mystr.filter { _ in defer { counter += 1 } return counter.isMultiple(of: 2) }
लियो डबस

अगर आप String.indexvar index = mystr.startIndex let result = mystr.filter { _ in defer { mystr.formIndex(after: &index) } return mystr.distance(from: mystr.startIndex, to: index).isMultiple(of: 2) }
Leo Dabus

0

यहां एक एक्सटेंशन दिया गया है जो आपको मानों के Intबजाय एक विकल्प की सीमा तक पहुंचने देगा String.Index:

import Foundation

/// This extension is available at
/// https://gist.github.com/zackdotcomputer/9d83f4d48af7127cd0bea427b4d6d61b
extension StringProtocol {
    /// Access the range of the search string as integer indices
    /// in the rendered string.
    /// - NOTE: This is "unsafe" because it may not return what you expect if
    ///     your string contains single symbols formed from multiple scalars.
    /// - Returns: A `CountableRange<Int>` that will align with the Swift String.Index
    ///     from the result of the standard function range(of:).
    func countableRange<SearchType: StringProtocol>(
        of search: SearchType,
        options: String.CompareOptions = [],
        range: Range<String.Index>? = nil,
        locale: Locale? = nil
    ) -> CountableRange<Int>? {
        guard let trueRange = self.range(of: search, options: options, range: range, locale: locale) else {
            return nil
        }

        let intStart = self.distance(from: startIndex, to: trueRange.lowerBound)
        let intEnd = self.distance(from: trueRange.lowerBound, to: trueRange.upperBound) + intStart

        return Range(uncheckedBounds: (lower: intStart, upper: intEnd))
    }
}

बस इस बात से अवगत रहें कि इससे अजीबता हो सकती है, यही वजह है कि Apple ने इसे कठिन बनाने के लिए चुना है। (हालांकि यह एक डिबेटेबल डिजाइन का निर्णय है - किसी खतरनाक चीज को सिर्फ कठिन बनाकर छिपाना ...)

आप Apple से स्ट्रिंग प्रलेखन में अधिक पढ़ सकते हैं , लेकिन tldr यह है कि यह इस तथ्य से उपजा है कि ये "सूचकांक" वास्तव में कार्यान्वयन-विशिष्ट हैं। वे ओएस द्वारा प्रस्तुत किए जाने के बाद स्ट्रिंग में सूचकांकों का प्रतिनिधित्व करते हैं , और इसलिए यूनिकोड कल्पना के किस संस्करण का उपयोग किया जा रहा है, इसके आधार पर ओएस-टू-ओएस से स्थानांतरित हो सकता है। इसका अर्थ है कि अनुक्रमणिका द्वारा मानों को एक्सेस करना अब एक निरंतर-समय का संचालन नहीं है, क्योंकि स्ट्रिंग में सही जगह निर्धारित करने के लिए UTF कल्पना को डेटा पर चलाया जाना है। यदि आप इसे पुल करते हैं, या अंतर्निहित UTF स्केलरों में सूचकांकों के साथ, ये सूचकांक NSString द्वारा उत्पन्न मूल्यों के साथ पंक्तिबद्ध नहीं होंगे। कैवियट डेवलपर।


दूरी को फिर से शुरू करने के लिए कोई ज़रूरत नहीं है। बस निचले से ऊपरी तक की दूरी प्राप्त करें और शुरुआत जोड़ें।
सिंह Dabus

मैं आपकी विधि में विकल्प भी जोड़ूंगा। कुछ इस तरहfunc rangeInt<S: StringProtocol>(of aString: S, options: String.CompareOptions = []) -> Range<Int>? { guard let range = range(of: aString, options: options) else { return nil } let start = distance(from: startIndex, to: range.lowerBound) return start..<start+distance(from: range.lowerBound, to: range.upperBound) }
लियो डबस

मैं शायद विधि का नाम countableRangeCountableRange
बदलकर

पूरे बोर्ड में अच्छे सुझाव @LeoDabus। मैंने सभी रेंज (की ...) दलीलों को जोड़ा, वास्तव में, इसलिए अब आप countableRange (of :, विकल्प :, रेंज:, लोकेल :) कह सकते हैं। जिस्ट को अपडेट किया है, इस पोस्ट को भी अपडेट करेंगे।
ज़ैक

मुझे इस बात की कोई आवश्यकता नहीं है कि यह विचार करने की ज़रूरत नहीं है कि आप उस विधि को एक विकल्प पर कह सकते हैं
लियो डबस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.