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

时间:2017-03-14 21:06:09

标签: swift string

与C一样,我们可以简单地做到

str[i] = str[j]

但是如何在swift中编写类似的逻辑呢? 这是我的代码,但得到了错误: 不能通过下标分配:下标是get-only

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

我知道它可能通过使用这种方法起作用,但它太不方便了

replaceSubrange(, with: )

3 个答案:

答案 0 :(得分:1)

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

例如:

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

对于单个修改,这看起来似乎很多,但如果你以这种方式移动很多字符,你只需要在每个方向转换一次。

反转字符串

这是一个用于反转字符串的简单算法的示例。通过首先转换为字符数组,此算法类似于您在C中执行此操作的方式:

let str = "abcdefg"
var strchars = Array(str.characters)

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"

答案 1 :(得分:0)

使用Swift处理String是a **的主要痛苦。与大多数语言不同,我知道将字符串视为字符数组,Swift将字符串视为扩展字形集群的集合,并且访问它们的API非常笨拙。 Changes are coming in 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

答案 2 :(得分:0)

Swift使字符串索引变得如此复杂,这一事实也让我感到震惊。因此,我构建了一些字符串扩展名,使您能够基于索引,闭合范围和打开范围,PartialRangeFrom,PartialRangeThrough和PartialRangeUpTo检索和更改字符串的一部分。您可以下载我创建的存储库here

您也可以传入数字,以便从末尾开始访问字符。

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"

以上所有方法也可以与分配一起使用。所有下标都有getter和setter。