Chcę przekonwertować indeks litery zawartej w ciągu na wartość całkowitą. Podjęto próbę odczytania plików nagłówkowych, ale nie mogę znaleźć typu dla Index
, chociaż wydaje się, że jest zgodny z protokołem ForwardIndexType
z metodami (np 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)
Każda pomoc jest mile widziana.
let index = letters.characters.index(of: "c")
następna linialet int_index = letters.characters.distance(from: letters.startIndex, to: index)
Odpowiedzi:
edytuj / aktualizuj:
Xcode 11 • Swift 5.1 lub nowszy
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) } }
Testy na placach zabaw
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") }
źródło
Szybki 4
var str = "abcdefg" let index = str.index(of: "c")?.encodedOffset // Result: 2
Uwaga: jeśli Ciąg zawiera te same wiele znaków, po prostu pobierze najbliższy od lewej
var str = "abcdefgc" let index = str.index(of: "c")?.encodedOffset // Result: 2
źródło
"🇺🇸🇺🇸🇧🇷".index(of: "🇧🇷")?.encodedOffset // 16
encodedOffset
wycofał się z wersji Swift 4.2 .Komunikat o wycofaniu :
encodedOffset
został wycofany, ponieważ najczęstsze użycie jest nieprawidłowe. Użyj,utf16Offset(in:)
aby osiągnąć to samo zachowanie.Więc możemy użyć w
utf16Offset(in:)
ten sposób:var str = "abcdefgc" let index = str.index(of: "c")?.utf16Offset(in: str) // Result: 2
źródło
let str = "🇺🇸🇺🇸🇧🇷"
let index = str.firstIndex(of: "🇧🇷")?.utf16Offset(in: str)
// Wynik: 8Aby wykonać operację na łańcuchach w oparciu o indeks, nie można tego zrobić tradycyjnym podejściem numerycznym indeksu. ponieważ swift.index jest pobierany przez funkcję indeksów i nie jest typu Int. Mimo że String jest tablicą znaków, nadal nie możemy odczytać elementu po indeksie.
To jest frustrujące.
Tak więc, aby utworzyć nowy podciąg każdego parzystego znaku ciągu, sprawdź poniższy kod.
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)
Wyjście: acegikmoqsuwy
Z góry dziękuję
źródło
var counter = 0
let result = mystr.filter { _ in
defer { counter += 1 }
return counter.isMultiple(of: 2)
}
var index = mystr.startIndex
let result = mystr.filter { _ in
defer { mystr.formIndex(after: &index) }
return mystr.distance(from: mystr.startIndex, to: index).isMultiple(of: 2)
}
Oto rozszerzenie , które pozwoli ci uzyskać dostęp do granic podciągu jako
Int
s zamiastString.Index
wartości: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)) } }
Miej tylko świadomość, że może to prowadzić do dziwności, dlatego Apple zdecydowało się to utrudnić. (Chociaż jest to dyskusyjna decyzja projektowa - ukrywanie niebezpiecznej rzeczy tylko przez utrudnianie jej ...)
Możesz przeczytać więcej w dokumentacji String firmy Apple , ale tldr wynika z faktu, że te „indeksy” są w rzeczywistości specyficzne dla implementacji. Reprezentują one indeksy w ciągu znaków po wyrenderowaniu go przez system operacyjny , więc mogą przechodzić z systemu operacyjnego do systemu operacyjnego w zależności od używanej wersji specyfikacji Unicode. Oznacza to, że dostęp do wartości według indeksu nie jest już operacją działającą w czasie stałym, ponieważ specyfikacja UTF musi zostać przeprowadzona na danych, aby określić właściwe miejsce w ciągu. Te indeksy również nie będą zgodne z wartościami generowanymi przez NSString, jeśli połączysz się z nim, lub z indeksami do bazowych skalarów UTF. Caveat developer.
źródło
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)
}
countableRange
i wróciłbymCountableRange