简体   繁体   English

Swift 3.0 遍历 String.Index 范围

[英]Swift 3.0 iterate over String.Index range

The following was possible with Swift 2.2: 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:使用 3.0,我们会收到以下错误:

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).我正在尝试对 swift 中的字符串执行一个非常简单的操作——简单地遍历字符串的前半部分(或者更一般的问题:遍历字符串的范围)。

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])
}

You can traverse a string by using indices property of the characters property like this: 您可以使用characters属性的indices属性遍历字符串,如下所示:

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
}

From the documentation in section Strings and Characters - Counting Characters : 字符串和字符 - 计数字符部分中的文档

Extended grapheme clusters can be composed of one or more Unicode scalars. 扩展的字形集群可以由一个或多个Unicode标量组成。 This means that different characters—and different representations of the same character—can require different amounts of memory to store. 这意味着不同的字符和相同字符的不同表示可能需要不同的内存量来存储。 Because of this, characters in Swift do not each take up the same amount of memory within a string's representation. 因此,Swift中的字符不会在字符串表示中占用相同数量的内存。 As a result, the number of characters in a string cannot be calculated without iterating through the string to determine its extended grapheme cluster boundaries. 因此,如果不迭代字符串以确定其扩展的字形集群边界, 则无法计算字符串中的字符数

emphasis is my own. 重点是我自己的。

This will not work: 这不起作用:

let secondChar = letters[1] 
// error: subscript is unavailable, cannot subscript String with an Int

Another option is to use enumerated() eg: 另一种选择是使用enumerated()例如:

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

or for Swift 4 just use 或者对于Swift 4只是使用

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

Use the following: 使用以下内容:

for i in s.characters.indices[s.startIndex..<s.endIndex] {
  print(s[i])
}

Taken from Migrating to Swift 2.3 or Swift 3 from Swift 2.2 自从Swift 2.2迁移到Swift 2.3或Swift 3

Iterating over characters in a string is cleaner in Swift 4: 在Swift 4中迭代字符串中的字符更清晰:

let myString = "Hello World"    
for char in myString {
    print(char)
}

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. 如果要遍历String的字符,那么您可以简单地使用符合CollectionTypeStringCharacterView ,而不是显式访问String的索引,从而允许您访问整齐的子序列方法,例如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 */

If you'd like to treat the characters within the loop as strings, simply use String(ch) above. 如果您想将循环中的字符视为字符串,只需使用上面的String(ch)


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 eg a half-open ( from..<to ) range 关于下面的评论:如果您想访问一系列的CharacterView ,您可以轻松实现自己的CollectionType扩展(在Generator.ElementCharacter时指定),同时使用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 */

The best way to do this is :- 最好的方法是: -

 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])
}

for more details visit here 有关详细信息,请访问此处

Swift 4: 斯威夫特4:

let mi: String = "hello how are you?"
for i in mi {
   print(i)
}

To concretely demonstrate how to traverse through a range in a string in Swift 4, we can use the where filter in a for loop to filter its execution to the specified range: 为了具体演示如何遍历Swift 4中字符串中的范围,我们可以使用for循环中的where过滤器将其执行过滤到指定范围:

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) will print t , r and i iterateStringByRange("string", from: 1, to: 3)将打印tri

Swift 4.2 Swift 4.2

Simply: 只是:

let m = "alpha"
for i in m.indices {
   print(m[i])
}

When iterating over the indices of characters in a string, you seldom only need the index.遍历字符串中字符的索引时,很少只需要索引。 You probably also need the character at the given index.您可能还需要给定索引处的字符。 As specified by Paulo (updated for Swift 4+), string.indices will give you the indices of the characters.正如 Paulo 所指定的(针对 Swift 4+ 进行了更新), string.indices将为您提供字符的索引。 zip can be used to combine index and character: zip可用于组合索引和字符:

let string = "string"

// Define the range to conform to your needs
let range = string.startIndex..<string.index(string.startIndex, offsetBy: string.count / 2)
let substring = string[range]
// If the range is in the type "first x characters", like until the middle, you can use:
//  let substring = string.prefix(string.count / 2)

for (index, char) in zip(substring.indices, substring) {
    // index is the index in the substring
    print(char)
}

Note that using enumerated() will produce a pair of index and character, but the index is not the index of the character in the string.请注意,使用enumerated()会产生一对索引和字符,但索引不是字符在字符串中的索引。 It is the index in the enumeration, which can be different.它是枚举中的索引,可以不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM