在Swift中如何将字符转换为UInt8

7

我有一个Swift字符数组:

static let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]

我想对每个Character作为一个字节(UInt8)进行一些按位运算。比如说,我该如何将charArray[0]转换为UInt8呢?


UInt8只有8位。这不能容纳大多数字符。对于您的用例限制为US-ASCII是否可以? - Thilo
1
@Leo Dabus 这不是重复的问题,因为我想要转换一个字符而不是一个字符串。 - JBaczuk
1
更合适的重复问题:https://dev59.com/dWAf5IYBdhLWcg3w9mps - Thilo
@Leo Dabus 由你决定,但我猜目前唯一的方法是将其转换为字符串。也许会有更好的答案出现。 - JBaczuk
@Thilo,这更接近了,但不会转换为UInt8。 - JBaczuk
显示剩余5条评论
5个回答

17
你需要通过Character的字符串表示来转换成UInt8。但是,在[Character] -> [UInt8]转换中,你不需要显式地初始化数组;因为String.UTF8View(来自String.utf8)是一个CollectionType,你可以在String.UTF8View本身上应用一个map操作;使用UInt8初始化即可。即,
let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]
let asUInt8Array = String(charArray).utf8.map{ UInt8($0) }

print(asUInt8Array)
/* [83, 116, 114, 105, 110, 103] */

print(asUInt8Array.dynamicType)
/* Array<UInt8> */

关于您下面的评论(“与Objective-C相比,Swift的抽象程度让人感到沮丧”),如果您认为上述代码凌乱,可以将其包含在扩展中,该扩展受限于字符元素的SequenceType,从而更容易地在实践中使用。例如:
extension SequenceType where Generator.Element == Character {

    /* extension accessible as function */
    func asByteArray() -> [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }

    /* or, as @LeoDabus pointed out below (thanks!),
       use a computed property for this simple case  */
    var byteArray : [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }
}

使用示例:

let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]

/* use extension function */
let asUInt8Array = charArray.asByteArray()

/* or computed property */
let asUInt8Array = charArray.byteArray

这真让人沮丧,Swift 太抽象了。而在 Objective-C 中非常简单。 - JBaczuk
@JBaczuk 我对 Obj-C 不是很熟悉,但通常来说,作为一种“安全”的语言,一些“限制”最终会进入该语言,与一个不太安全但在某些情况下可能更灵活的语言相比,就某些低级操作而言。然而,由于 Swift 允许对本地类型进行扩展,因此您可以轻松创建自己的包装器以简化您认为不简单的代码。例如,我将添加一个使用 SequenceType 扩展的解决方案版本,其中 Generator.Element 限制为 Character 类型。 - dfrib
这会让它更简单,没错,好答案,只是对Swift感到沮丧,仅此而已。它只对某些事情“迅速”。 - JBaczuk
当扩展任何方法时,如果你需要传递给该方法的只是元素本身,那么你可以使用计算属性,例如 var bytesArray: [UInt8] { return ... } - Leo Dabus
1
@LeoDabus 你说得对,既然我们不会抛出任何异常之类的东西,那么计算属性更适合,谢谢!(等我不在移动设备上时会在答案中包含)。 - dfrib

4
我不确定如何将一个字符转换为UTF-8,但是一个字符串有一个utf8属性,所以你可以使用以下方法:
let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]
let string = Array(String(charArray).utf8)
print(string)

那是一个可行的想法,但肯定有更好的方法。 - JBaczuk
你知道一个字符可能会超过一个UTF-8字节吗? - Michael

2
这是我最终采取的做法:
var char: Character = "a"
var byte: UInt8 = Array(String(char).utf8)[0]

一定有更好的方法...


我也是这么想的。这似乎可以解决问题:char.asciiValue!"a".utf8.first! - P. A. Monsaille

1

Swift 5:

let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]

var oneAscii: UInt8 = charArray[0].asciiValue!

当然,如果您的输入不是ASCII字符集中的文字,您需要确保结果不是nil。

1
这是有风险的,因为强制解包可能会导致应用程序崩溃,特别是如果字符的来源在开发者控制之下。 - Cristik
没错,我只是展示了一个简单的解决方案示例,而不是我实际使用的经过仔细检查的版本。在我的情况下,我正在使用一个字面量,所以我知道它可以工作。如果输入范围可能会失败,那么就需要检查一些东西...我会添加一个警告。 - Hack Saw

0

为了改进@dfri的答案https://dev59.com/k5Xfa4cB1Zd3GeqPaBt1#36025104

对于Swift 3,您必须使用以下内容:

extension Sequence where Iterator.Element == Character {

    /* extension accessible as function */
    func asByteArray() -> [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }

    /* or, as @LeoDabus pointed out below (thanks!),
     use a computed property for this simple case  */
    var byteArray : [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接