有没有一种方法在Swift中从utf16数组创建字符串?

10
我们知道 String.utf16 提供了 codeunits,而 String.unicodeScalars 则提供了 scalars。
如果我们通过删除一些元素等来操作 codeunits 和 unicodeScales,那么有没有一种方法可以构建出产生的字符串呢?
3个回答

9

Swift 2.1更新:

你可以使用以下方法从一个UTF-16字符数组中创建一个String

public init(utf16CodeUnits: UnsafePointer<unichar>, count: Int)

初始化程序。例如:
let str = "H€llo "

// String to UTF16 array:
let utf16array = Array(str.utf16)
print(utf16array)
// Output: [72, 8364, 108, 108, 111, 32, 55357, 56836]

// UTF16 array to string:
let str2 = String(utf16CodeUnits: utf16array, count: utf16array.count)
print(str2)
// H€llo 

之前的回答:

据我所知,Python中没有内置的方法用于此问题,但您可以使用UTF16结构体并调用其中的decode()方法:

extension String {

    init?(utf16chars:[UInt16]) {
        var str = ""
        var generator = utf16chars.generate()
        var utf16 : UTF16 = UTF16()
        var done = false
        while !done {
            let r = utf16.decode(&generator)
            switch (r) {
            case .EmptyInput:
                done = true
            case let .Result(val):
                str.append(Character(val))
            case .Error:
                return nil
            }
        }
        self = str
    }
}

例子:

let str = "H€llo "

// String to UTF16 array:
let utf16array = Array(str.utf16)
print(utf16array)
// Output: [72, 8364, 108, 108, 111, 32, 55357, 56836]

// UTF16 array to string:
if let str2 = String(utf16chars: utf16array) {
    print(str2)
    // Output: H€llo 
}

略微更加通用的方式是定义一个方法,使用给定的编解码器从代码点数组(或任何序列)创建字符串:

稍微泛化一下,你可以定义一个方法,使用给定的编解码器从代码点数组(或任何序列)中创建字符串:

extension String {
    init?<S : SequenceType, C : UnicodeCodecType where S.Generator.Element == C.CodeUnit>
        (codeUnits : S, var codec : C) {
        var str = ""
        var generator = codeUnits.generate()
        var done = false
        while !done {
            let r = codec.decode(&generator)
            switch (r) {
            case .EmptyInput:
                done = true
            case let .Result(val):
                str.append(Character(val))
            case .Error:
                return nil
            }
        }
        self = str
    }
}

然后,将UTF16转换完成为:
if let str2a = String(codeUnits: utf16array, codec: UTF16()) {
    print(str2a)
}

这里是另一个可能的解决方案。虽然之前的方法是“纯Swift”,但是这个方法使用Foundation框架和NSString与Swift String之间的自动桥接:

extension String {

    init?(utf16chars:[UInt16]) {
        let data = NSData(bytes: utf16chars, length: utf16chars.count * sizeof(UInt16))
        if let ns = NSString(data: data, encoding: NSUTF16LittleEndianStringEncoding) {
            self = ns as String
        } else {
            return nil
        }
    }
}

1
“while !done” 部分是我在 Swift 中发现标记式 break 很有用的少数情况之一,例如: end: while true … case .EmptyInput: break end - Airspeed Velocity

1
答案就像这样简单:
/// An array of the UTF-16 for "Hello, world!".
let a: [UTF16.CodeUnit] = Array("Hello, world!".utf16)

/// A string representation of a, interpreted as UTF-16
let s = String(decoding: a, as: UTF16.self) // <=== The API you want
print(s)


或者简单地使用String(utf16CodeUnits: a, count: a.count) - Leo Dabus
那个需要基础,使用了不安全的API,并且不能推广到其他集合和编码。 - Dave Abrahams
问题是:在Swift中是否有一种方法可以从UTF16数组创建字符串?在大多数情况下,导入Foundation不应该是一个问题。 - Leo Dabus

0

就是这个。

extension String {
    static func fromUTF16Chars(utf16s:UInt16[]) -> String {
        var str = ""
        for var i = 0; i < utf16s.count; i++ {
            let hi = Int(utf16s[i])
            switch hi {
            case 0xD800...0xDBFF:
                let lo = Int(utf16s[++i])
                let us = 0x10000
                    + (hi - 0xD800)*0x400 + (lo - 0xDC00)
                str += Character(UnicodeScalar(us))
            default:
                str += Character(UnicodeScalar(hi))
            }
        }
        return str
    }
}

let str = "aαあaαあ"
var utf16cs = UInt16[]()
for utf16c in str.utf16 {
    utf16cs += utf16c
}
let str2 = String.fromUTF16Chars(utf16cs)
assert(str2 == str)
println(str2)

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