有没有办法在swift中从utf16数组创建一个String?

时间:2014-07-02 22:36:02

标签: string swift bytearray

我们知道String.utf16提供了codeunits或String.unicodeScalars提供了标量。

如果我们通过删除一些元素来操纵codeunits和unicodeScales等,有没有办法构造回结果字符串?

3 个答案:

答案 0 :(得分:7)

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 

上一个回答:

没有什么&#34;内置&#34; (据我所知),但您可以使用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&#34;,但是这个方法使用了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 :(得分: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)

答案 2 :(得分:0)

@MartinR answer已更新为 Swift 4

第一个解决方案需要导入Foundation:

import Foundation

extension String {
    init(utf16chars: [UInt16]) {
        self.init(utf16CodeUnits: utf16chars, count: utf16chars.count)
    }
}

另一种仅使用Swift的解决方案(使用@Airspeed Velocity的注释中建议的带标签的中断):

extension String {
    init?(utf16chars : [UInt16]) {
        var unicodeScalars: [Unicode.Scalar] = []
        var iterator = utf16chars.makeIterator()
        var utf16 = UTF16()
        end: while true {
            switch utf16.decode(&iterator) {
            case .emptyInput:
                break end
            case .scalarValue(let unicodeScalar):
                unicodeScalars.append(unicodeScalar)
            case .error:
                return nil
            }
        }
        self.init(UnicodeScalarView(unicodeScalars))
    }
}