Swift 3.0 итерации по диапазону String.Index
В Swift 2.2 возможно следующее:
let m = "alpha"
for i in m.startIndex..<m.endIndex {
print(m[i])
}
a
l
p
h
a
С 3.0 мы получаем следующую ошибку:
Тип 'Range' (aka 'Range') не соответствует протоколу 'Sequence'
Я пытаюсь выполнить очень простую операцию со строками в swift - просто перейдите через первую половину строки (или более общую проблему: перейдите через ряд строк).
Я могу сделать следующее:
let s = "string"
var midIndex = s.index(s.startIndex, offsetBy: s.characters.count/2)
let r = Range(s.startIndex..<midIndex)
print(s[r])
Но здесь я действительно не пересекаю строку. Поэтому возникает вопрос: как мне пройти через диапазон заданной строки. Как:
for i in Range(s.startIndex..<s.midIndex) {
print(s[i])
}
Ответы
Ответ 1
Вы можете пройти строку, используя свойство indices
свойства characters
например:
let letters = "string"
let middle = letters.index(letters.startIndex, offsetBy: letters.characters.count / 2)
for index in letters.characters.indices {
// to traverse to half the length of string
if index == middle { break } // s, t, r
print(letters[index]) // s, t, r, i, n, g
}
Из документации в разделе Строки и символы - Подсчет символов:
Расширенные кластеры графем могут состоять из одного или нескольких скаляров Unicode. Это означает, что различным символам - и различным представлениям одного и того же символа - может потребоваться различное количество памяти для хранения. Из-за этого символы в Swift не занимают одинаковое количество памяти в строковом представлении. В результате количество символов в строке не может быть рассчитано без итерации по строке для определения границ кластера расширенных графем.
акцент мой.
Это не будет работать:
let secondChar = letters[1]
// error: subscript is unavailable, cannot subscript String with an Int
Ответ 2
Другой вариант - использовать enumerated()
например:
let string = "Hello World"
for (index, char) in string.characters.enumerated() {
print(char)
}
или для Swift 4 просто используйте
let string = "Hello World"
for (index, char) in string.enumerated() {
print(char)
}
Ответ 3
Используйте следующее:
for i in s.characters.indices[s.startIndex..<s.endIndex] {
print(s[i])
}
Взято из миграции в Swift 2.3 или Swift 3 из Swift 2.2
Ответ 4
Перебор символов в строке более понятен в Swift 4:
let myString = "Hello World"
for char in myString {
print(char)
}
Ответ 5
Если вы хотите пересечь символы String
, то вместо явного доступа к индексам String
вы можете просто работать с CharacterView
String
, который соответствует CollectionType
, что позволяет получить доступ к аккуратным методам подпоследовательности, таким как prefix(_:)
и т.д.
/* traverse the characters of your string instance,
up to middle character of the string, where "middle"
will be rounded down for strings of an odd amount of
characters (e.g. 5 characters -> travers through 2) */
let m = "alpha"
for ch in m.characters.prefix(m.characters.count/2) {
print(ch, ch.dynamicType)
} /* a Character
l Character */
/* round odd division up instead */
for ch in m.characters.prefix((m.characters.count+1)/2) {
print(ch, ch.dynamicType)
} /* a Character
l Character
p Character */
Если вы хотите обрабатывать символы в цикле как строки, просто используйте String(ch)
выше.
Что касается вашего комментария ниже: если вы хотите получить доступ к диапазону CharacterView
, вы можете легко реализовать собственное расширение CollectionType
(указанное для Generator.Element
is Character
), используя как prefix(_:)
, так и suffix(_:)
, чтобы получить подсерию, например, полуоткрытый (from..<to
) диапазон
/* for values to >= count, prefixed CharacterView will be suffixed until its end */
extension CollectionType where Generator.Element == Character {
func inHalfOpenRange(from: Int, to: Int) -> Self {
guard case let to = min(to, underestimateCount()) where from <= to else {
return self.prefix(0) as! Self
}
return self.prefix(to).suffix(to-from) as! Self
}
}
/* example */
let m = "0123456789"
for ch in m.characters.inHalfOpenRange(4, to: 8) {
print(ch) /* \ */
} /* 4 a (sub-collection) CharacterView
5
6
7 */
Ответ 6
Лучший способ сделать это: -
let name = "nick" // The String which we want to print.
for i in 0..<name.count
{
// Operation name[i] is not allowed in Swift, an alternative is
let index = name.index[name.startIndex, offsetBy: i]
print(name[index])
}
Подробнее см. здесь
Ответ 7
Свифт 4:
let mi: String = "hello how are you?"
for i in mi {
print(i)
}
Ответ 8
Чтобы конкретно продемонстрировать, как проходить через диапазон в строке в Swift 4, мы можем использовать фильтр where
в цикле for
для фильтрации его выполнения в указанном диапазоне:
func iterateStringByRange(_ sentence: String, from: Int, to: Int) {
let startIndex = sentence.index(sentence.startIndex, offsetBy: from)
let endIndex = sentence.index(sentence.startIndex, offsetBy: to)
for position in sentence.indices where (position >= startIndex && position < endIndex) {
let char = sentence[position]
print(char)
}
}
iterateStringByRange("string", from: 1, to: 3)
выведет t
, r
и i
Ответ 9
Swift 4.2
Просто:
let m = "alpha"
for i in m.indices {
print(m[i])
}