我怎样才能得到字符串的第n个字符?我尝试了括号([])访问器,没有运气。

var string = "Hello, world!"

var firstChar = string[0] // Throws error

错误:'下标'是不可用的:不能下标String与Int,请参阅文档注释讨论


当前回答

斯威夫特5.2

let str = "abcdef"
str[1 ..< 3] // returns "bc"
str[5] // returns "f"
str[80] // returns ""
str.substring(fromIndex: 3) // returns "def"
str.substring(toIndex: str.length - 2) // returns "abcd"

你需要将这个String扩展添加到你的项目中(它已经完全测试过了):

extension String {

    var length: Int {
        return count
    }

    subscript (i: Int) -> String {
        return self[i ..< i + 1]
    }

    func substring(fromIndex: Int) -> String {
        return self[min(fromIndex, length) ..< length]
    }

    func substring(toIndex: Int) -> String {
        return self[0 ..< max(0, toIndex)]
    }

    subscript (r: Range<Int>) -> String {
        let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                            upper: min(length, max(0, r.upperBound))))
        let start = index(startIndex, offsetBy: range.lowerBound)
        let end = index(start, offsetBy: range.upperBound - range.lowerBound)
        return String(self[start ..< end])
    }
}

尽管Swift总是有开箱即用的解决方案来解决这个问题(没有字符串扩展,我在下面提供),我仍然强烈建议使用扩展。为什么?因为它为我从早期版本的Swift中节省了数十个小时的痛苦迁移,在早期版本中,String的语法几乎每次发布都要更改,但我所需要做的只是更新扩展的实现,而不是重构整个项目。做出你的选择。

let str = "Hello, world!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // returns Character 'o'

let endIndex = str.index(str.endIndex, offsetBy:-2)
str[index ..< endIndex] // returns String "o, worl"

String(str.suffix(from: index)) // returns String "o, world!"
String(str.prefix(upTo: index)) // returns String "Hell"

其他回答

使用字符就可以了。您可以快速地将字符串转换为字符数组,可以由CharacterView方法操作。

例子:

let myString = "Hello World!"
let myChars  = myString.characters

(完整的CharacterView文档)

(在Swift 3中测试)

斯威夫特5.3

我觉得这很优雅。“Hacking with Swift”的Paul Hudson提出了以下解决方案:

@available (macOS 10.15, * )
extension String {
    subscript(idx: Int) -> String {
        String(self[index(startIndex, offsetBy: idx)])
    }
}

然后,要从字符串中获取一个字符,你只需做:

var string = "Hello, world!"

var firstChar = string[0] // No error, returns "H" as a String

注意:我只是想补充,这将返回一个字符串指出在评论。我认为这对Swift用户来说可能是意想不到的,但我经常需要一个字符串来直接在我的代码中使用,而不是字符类型,所以它确实简化了我的代码,避免了后来从字符到字符串的转换。

斯威夫特4.2

这个答案是理想的,因为它在一个扩展中扩展了String及其所有子序列(Substring)

public extension StringProtocol {
    
    public subscript (i: Int) -> Element {
        return self[index(startIndex, offsetBy: i)]
    }

    public subscript (bounds: CountableClosedRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start...end]
    }
    
    public subscript (bounds: CountableRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start..<end]
    }
    
    public subscript (bounds: PartialRangeUpTo<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex..<end]
    }
    
    public subscript (bounds: PartialRangeThrough<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex...end]
    }
    
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        return self[start..<endIndex]
    }
}

使用

var str = "Hello, playground"

print(str[5...][...5][0])
// Prints ","

Swift 4.2或更高版本

使用String的indexes属性进行范围和部分范围下标

作为@LeoDabus nice answer的变体,我们可以为DefaultIndices添加一个额外的扩展,目的是允许我们在为后者实现自定义下标(通过Int专用范围和部分范围)时使用String的indexes属性。

extension DefaultIndices {
    subscript(at: Int) -> Elements.Index { index(startIndex, offsetBy: at) }
}

// Moving the index(_:offsetBy:) to an extension yields slightly
// briefer implementations for these String extensions.
extension String {
    subscript(range: Range<Int>) -> SubSequence {
        let start = indices[range.lowerBound]
        return self[start..<indices[start...][range.count]]
    }
    subscript(range: ClosedRange<Int>) -> SubSequence {
        let start = indices[range.lowerBound]
        return self[start...indices[start...][range.count]]
    }
    subscript(range: PartialRangeFrom<Int>) -> SubSequence {
        self[indices[range.lowerBound]...]
    }
    subscript(range: PartialRangeThrough<Int>) -> SubSequence {
        self[...indices[range.upperBound]]
    }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence {
        self[..<indices[range.upperBound]]
    }
}

let str = "foo bar baz bax"
print(str[4..<6]) // "ba"
print(str[4...6]) // "bar"
print(str[4...])  // "bar baz bax"
print(str[...6])  // "foo bar"
print(str[..<6])  // "foo ba"

感谢@LeoDabus指出我在使用索引属性作为字符串下标的(其他)替代方案的方向!

你也可以像这样将字符串转换为字符数组:

let text = "My Text"
let index = 2
let charSequence = text.unicodeScalars.map{ Character($0) }
let char = charSequence[index]

这是在常数时间内在指定索引处获取char的方法。

下面的示例不是在常数时间内运行,而是需要线性时间。所以如果你有很多搜索字符串索引使用上述方法。

let char = text[text.startIndex.advancedBy(index)]