在Swift中,如何使用下标在字符串中修改字符



喜欢在C中,我们可以简单地做

str[i] = str[j]

但是如何在Swift中写类似的逻辑?这是我的代码,但有错误:无法通过下标分配:下标是仅

let indexI = targetString.index(targetString.startIndex, offsetBy: i)
let indexJ = targetString.index(targetString.startIndex, offsetBy: j)        
targetString[indexI] = targetString[indexJ]

我知道它可能会使用这种方法来工作,但这太不便了

replaceSubrange(, with: )

在C中,字符串(char *)可以视为字符数组。在Swift中,您可以将String转换为[Character],进行所需的修改,然后将[Character]转换回String

例如:

let str = "hello"    
var strchars = Array(str)    
strchars[0] = strchars[4]    
let str2 = String(strchars)
print(str2) // "oello"

这似乎是一次修改的工作,但是如果您以这种方式移动许多角色,则只需转换一次每个方向。


反向字符串

这是一种简单算法来反向字符串的示例。首先通过转换为字符数组,该算法类似于您在C中可能执行的方式:

let str = "abcdefg"
var strchars = Array(str)
var start = 0
var end = strchars.count - 1
while start < end {
    let temp = strchars[start]
    strchars[start] = strchars[end]
    strchars[end] = temp
    start += 1
    end -= 1
}
let str2 = String(strchars)
print(str2)  // "gfedcba"

用swift处理 String是a **的主要痛苦。与大多数语言不同,我知道将字符串视为一系列字符,Swift将字符串视为扩展的grupheme clupters 的集合,而访问它们的API确实很笨拙。Swift 4的变化正在发生,但该宣言让我失去了大约10段。

回到您的问题...您可以替换这样的角色:

var targetString = "Hello world"
let i = 0
let j = 1
let indexI = targetString.index(targetString.startIndex, offsetBy: i)
let indexJ = targetString.index(targetString.startIndex, offsetBy: j)
targetString.replaceSubrange(indexI...indexI, with: targetString[indexJ...indexJ])
print(targetString) // eello world

我也对Swift使字符串索引如此复杂的事实也感到震惊。因此,我构建了一些弦乐扩展,使您能够根据索引,封闭范围和开放范围,partrangefrom,partialrangethrough和partialrangeupto检索和更改字符串的部分。您可以下载我在此处创建的存储库

您也可以传递负面数字,以便从末端访问字符。

public extension String {
    /**
     Enables passing in negative indices to access characters
     starting from the end and going backwards.
     if num is negative, then it is added to the
     length of the string to retrieve the true index.
     */
    func negativeIndex(_ num: Int) -> Int {
        return num < 0 ? num + self.count : num
    }
    func strOpenRange(index i: Int) -> Range<String.Index> {
        let j = negativeIndex(i)
        return strOpenRange(j..<(j + 1), checkNegative: false)
    }
    func strOpenRange(
        _ range: Range<Int>, checkNegative: Bool = true
    ) -> Range<String.Index> {
        var lower = range.lowerBound
        var upper = range.upperBound
        if checkNegative {
            lower = negativeIndex(lower)
            upper = negativeIndex(upper)
        }
        let idx1 = index(self.startIndex, offsetBy: lower)
        let idx2 = index(self.startIndex, offsetBy: upper)
        return idx1..<idx2
    }
    func strClosedRange(
        _ range: CountableClosedRange<Int>, checkNegative: Bool = true
    ) -> ClosedRange<String.Index> {
        var lower = range.lowerBound
        var upper = range.upperBound
        if checkNegative {
            lower = negativeIndex(lower)
            upper = negativeIndex(upper)
        }
        let start = self.index(self.startIndex, offsetBy: lower)
        let end = self.index(start, offsetBy: upper - lower)
        return start...end
    }
    // MARK: - Subscripts
    /**
     Gets and sets a character at a given index.
     Negative indices are added to the length so that
     characters can be accessed from the end backwards
     Usage: `string[n]`
     */
    subscript(_ i: Int) -> String {
        get {
            return String(self[strOpenRange(index: i)])
        }
        set {
            let range = strOpenRange(index: i)
            replaceSubrange(range, with: newValue)
        }
    }

    /**
     Gets and sets characters in an open range.
     Supports negative indexing.
     Usage: `string[n..<n]`
     */
    subscript(_ r: Range<Int>) -> String {
        get {
            return String(self[strOpenRange(r)])
        }
        set {
            replaceSubrange(strOpenRange(r), with: newValue)
        }
    }
    /**
     Gets and sets characters in a closed range.
     Supports negative indexing
     Usage: `string[n...n]`
     */
    subscript(_ r: CountableClosedRange<Int>) -> String {
        get {
            return String(self[strClosedRange(r)])
        }
        set {
            replaceSubrange(strClosedRange(r), with: newValue)
        }
    }
    /// `string[n...]`. See PartialRangeFrom
    subscript(r: PartialRangeFrom<Int>) -> String {
        get {
            return String(self[strOpenRange(r.lowerBound..<self.count)])
        }
        set {
            replaceSubrange(strOpenRange(r.lowerBound..<self.count), with: newValue)
        }
    }
    /// `string[...n]`. See PartialRangeThrough
    subscript(r: PartialRangeThrough<Int>) -> String {
        get {
            let upper = negativeIndex(r.upperBound)
            return String(self[strClosedRange(0...upper, checkNegative: false)])
        }
        set {
            let upper = negativeIndex(r.upperBound)
            replaceSubrange(
                strClosedRange(0...upper, checkNegative: false), with: newValue
            )
        }
    }
    /// `string[...<n]`. See PartialRangeUpTo
    subscript(r: PartialRangeUpTo<Int>) -> String {
        get {
            let upper = negativeIndex(r.upperBound)
            return String(self[strOpenRange(0..<upper, checkNegative: false)])
        }
        set {
            let upper = negativeIndex(r.upperBound)
            replaceSubrange(
                strOpenRange(0..<upper, checkNegative: false), with: newValue
            )
        }
    }

}

用法:

let text = "012345"
print(text[2]) // "2"
print(text[-1] // "5"
print(text[1...3]) // "123"
print(text[2..<3]) // "2"
print(text[3...]) // "345"
print(text[...3]) // "0123"
print(text[..<3]) // "012"
print(text[(-3)...] // "345"
print(text[...(-2)] // "01234"

上述所有操作都与分配一起工作。所有下标都有Getters和setter。

添加了新的扩展名,

因为String符合BidirectionalCollection协议

extension String{
    subscript(at i: Int) -> String? {
            get {
                if i < count{
                    let idx = index(startIndex, offsetBy: i)
                    return String(self[idx])
                }
                else{
                    return nil
                }
            }
            set {
                if i < count{
                    let idx = index(startIndex, offsetBy: i)
                    remove(at: idx)
                    if let new = newValue, let first = new.first{
                        insert(first, at: idx)
                    }
                }
            }
        }
}

这样打电话:

var str = "fighter"
str[at: 2] = "6"

最新更新