Swift 3.0 iterate over String.Index range

2019-01-25 02:43发布

The following was possible with Swift 2.2:

let m = "alpha"
for i in m.startIndex..<m.endIndex {
    print(m[i])
}
a
l
p
h
a

With 3.0, we get the following error:

Type 'Range' (aka 'Range') does not conform to protocol 'Sequence'

I am trying to do a very simple operation with strings in swift -- simply traverse through the first half of the string (or a more generic problem: traverse through a range of a string).

I can do the following:

let s = "string"
var midIndex = s.index(s.startIndex, offsetBy: s.characters.count/2)
let r = Range(s.startIndex..<midIndex)
print(s[r])

But here I'm not really traversing the string. So the question is: how do I traverse through a range of a given string. Like:

for i in Range(s.startIndex..<s.midIndex) {
    print(s[i])
}

标签: swift swift3
9条回答
小情绪 Triste *
2楼-- · 2019-01-25 03:21

Another option is to use enumerated() e.g:

let string = "Hello World"    
for (index, char) in string.characters.enumerated() {
    print(char)
}

or for Swift 4 just use

let string = "Hello World"    
for (index, char) in string.enumerated() {
    print(char)
}
查看更多
Bombasti
3楼-- · 2019-01-25 03:22

Swift 4:

let mi: String = "hello how are you?"
for i in mi {
   print(i)
}
查看更多
叼着烟拽天下
4楼-- · 2019-01-25 03:25

If you want to traverse over the characters of a String, then instead of explicitly accessing the indices of the String, you could simply work with the CharacterView of the String, which conforms to CollectionType, allowing you access to neat subsequencing methods such as prefix(_:) and so on.

/* 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 */

If you'd like to treat the characters within the loop as strings, simply use String(ch) above.


With regard to your comment below: if you'd like to access a range of the CharacterView, you could easily implement your own extension of CollectionType (specified for when Generator.Element is Character) making use of both prefix(_:) and suffix(_:) to yield a sub-collection given e.g. a half-open (from..<to) range

/* 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 */
查看更多
登录 后发表回答