如何将 UTF16 字符串解码为 Unicode 字符



设备将字符串"🤛🏽编码为"uD83EuDD1BuD83CuDFFD"。此字符串中表示的十六进制数字来自字符的 UTF-16 十六进制编码。Unicode 码位U+1F91B, U+1F3FD从 UTF-32 十六进制编码中获取其编号。

以后面的这个为例,在 Swift 中,我们可以做一个像这样的文字 "\u{1F91B}\u{1F3FD}",我们将按预期得到字符 "🤛🏽"。

如何从 UTF-16 十六进制字符串"uD83EuDD1BuD83CuDFFD"转换以获取"🤛🏽"?

我尝试获取字符串并将其转换为 32 位整数数组[UInt32]然后使用它来创建 unicode 标量,但这仅适用于可以用单个 UTF-32 码位表示的 Unicode 字符。

这是我正在使用的源代码。

extension String {
func decodeBlock() -> String {
let strings = self.components(separatedBy: "\u")
var scalars : [UInt32] = []

var value: UInt32 = 0
for string in strings {
print(string)
let scanner = Scanner(string: string)
if scanner.scanHexInt32(&value) {
scalars.append(value)
}
}

let utf32chars = scalars
var str = ""
var generator = utf32chars.makeIterator()
var utf32 : UTF32 = UTF32()
var done = false
while !done {
let r = utf32.decode(&generator)
switch (r) {
case . emptyInput:
done = true
case .scalarValue(let val):
str.append(Character(val))
case .error:
return "$"
}
}
return str

return self
}
}

它改编自类似问题的答案中的代码。 https://stackoverflow.com/a/41412056/731773

编码字符串的来源是 org.apache.commons.lang.StringEscapeUtilsescapeJava函数,可以在这里找到。

这有点作弊,但 UTF-16 恰好是NSString使用的编码,因此您可以借用NSString的方法来实现它:

extension String {
func decodeBlock() -> String? {
var chars = [unichar]()
for substr in self.components(separatedBy: "\u") where !substr.isEmpty {
if let value = UInt16(substr, radix: 16) {
chars.append(value)
} else {
return nil
}
}
return NSString(characters: chars, length: chars.count) as String
}
}
if let decoded = "\uD83E\uDD1B\uD83C\uDFFD".decodeBlock() {
print(decoded)
} else {
print("Cannot decode")
}

这绝对是作弊,因为它只是使用 JavaScript 中的内置方法,但它有效。

func decode() -> String{
// getting a JSContext
let context = JSContext()
let encodedString = self
// defining a JavaScript function
let jsFunctionText = "var decode = function(encodedString) {n" +
"var r = /\\u([\d\w]{4})/gi;n" +
" x = encodedStringn" +
"x = x.replace(r, function (match, grp) {n" +
"     return String.fromCharCode(parseInt(grp, 16)); } );n" +
" x = unescape(x);n" +
" return xn" +
"}"
//    print(jsFunctionText)
context!.evaluateScript(jsFunctionText)!
// calling a JavaScript function
let jsFunction = context?.objectForKeyedSubscript("decode")
let decodedValue = jsFunction?.call(withArguments: [encodedString]);
if let decodedString = decodedValue?.toString() {
return decodedString
} else {
return self
}
}

最新更新