将 Swift 字符串切割成 2 个字母的字符串的最佳方法是什么?

What's the best way to cut Swift string into 2-letter-strings?

我需要将一个字符串拆分为 2 个字母的片段。 Like “friend” -> "fr" "ie" "nd"。(好吧,这是我将HEX字符串更改为Uint8数组的一步)

我的密码是

    for i=0; i<chars.count/2; i++ {
        let str = input[input.startIndex.advancedBy(i*2)..<input.startIndex.advancedBy(i*2+1)]
        bytes.append(UInt8(str,radix: 16)!)
    }

但是我不知道为什么我不能使用Range来做这个分割。而且我不知道当 i*2+1 大于字符串的长度时会发生什么。那么将 Swift 字符串切割成 2 个字母的字符串的最佳方法是什么?

您的范围无效,因为您需要使用 ... 而不是 ..<

let input = "ff103"
var bytes = [UInt8]()

let strlen = input.characters.count
for i in 0 ..< (strlen + 1)/2 {
    let str = input[input.startIndex.advancedBy(i*2)...input.startIndex.advancedBy(min(strlen - 1, i*2+1))]
    bytes.append(UInt8(str,radix: 16) ?? 0)
}

print(bytes)  // [255, 16, 3]

这是将字符串拆分为 2 个字母的字符串的另一种方法。 advancedBy() 是一个 昂贵的 O(n) 操作,所以这个版本跟踪 start 并在每个循环中向前推进 2,并且end 基于 start:

let input = "friends"
var strings = [String]()

let strlen = input.characters.count
var start = input.startIndex
let lastIndex = strlen > 0 ? input.endIndex.predecessor() : input.startIndex

for i in 0 ..< (strlen + 1)/2 {
    start = i > 0 ? start.advancedBy(2) : start
    let end = start < lastIndex ? start.successor() : start
    let str = input[start...end]
    strings.append(str)
}

print(strings) // ["fr", "ie", "nd", "s"]

备选答案:

使用范围可能有点矫枉过正。只需将字符添加到数组并从中生成 Strings 就很容易:

let input = "friends"
var strings = [String]()
var newchars = [Character]()

for c in input.characters {
    newchars.append(c)
    if newchars.count == 2 {
        strings.append(String(newchars))
        newchars = []
    }
}

if newchars.count > 0 {
    strings.append(String(newchars))
}

print(strings) // ["fr", "ie", "nd", "s"]

这是制作 [UInt8]:

的新版本
let input = "ff103"
var bytes = [UInt8]()
var newchars = [Character]()

for c in input.characters {
    newchars.append(c)
    if newchars.count == 2 {
        bytes.append(UInt8(String(newchars), radix: 16) ?? 0)
        newchars = []
    }
}

if newchars.count > 0 {
    bytes.append(UInt8(String(newchars), radix: 16) ?? 0)
}

print(bytes) // [255, 16, 3]

根据@LeoDabus 的回答,我们可以使用一种方法进行扩展,该方法将 return 任意长度的子字符串,以及 计算的 属性 returns [UInt8]:

extension String {
    func substringsOfLength(length: Int) -> [String] {
        if length < 1 { return [] }

        var result:[String] = []
        let chars = Array(characters)
        for index in 0.stride(to: chars.count, by: length) {
            result.append(String(chars[index ..< min(index+length, chars.count)]))
        }
        return result
    }

    var toUInt8: [UInt8] {
        var result:[UInt8] = []
        let chars = Array(characters)
        for index in 0.stride(to: chars.count, by: 2) {
            let str = String(chars[index ..< min(index+2, chars.count)])
            result.append(UInt8(str, radix: 16) ?? 0)
        }
        return result
    }
}

let input = "friends"
let str2 = input.substringsOfLength(2)  // ["fr", "ie", "nd", "s"]
let str0 = input.substringsOfLength(0)  // []
let str3 = input.substringsOfLength(3)  // ["fri", "end", "s"]

let bytes = "ff107".toUInt8  // [255, 16, 7]

另一个娱乐选项:

extension String {
    var pairs:[String] {
        var result:[String] = []
        let chars = Array(characters)
        for index in 0.stride(to: chars.count, by: 2) {
            result.append(String(chars[index..<min(index+2, chars.count)]))
        }
        return result
    }
}
let input = "friends"
let pairs = input.pairs
print(pairs) // ["fr", "ie", "nd", "s"]