简体   繁体   English

十六进制字符串到PURE Swift中的字符

[英]Hex String to Character in PURE Swift

I need a way to convert a string that contains a literal string representing a hexadecimal value into a Character corresponding to that particular hexadecimal value. 我需要一种将包含表示十六进制值的文字字符串的字符串转换为与该特定十六进制值相对应的Character的方法。

Ideally, something along these lines: 理想情况下,遵循以下原则:

let hexString: String = "2C"
let char: Character = fromHexString(hexString)
println(char)   // prints -> ","

I've tried to use the syntax: "\\u{n}\u0026quot; where n is a Int or String and neither worked. 我尝试使用语法:“ \\ u {n}”,其中n是Int或String,但都不起作用。

This could be used to loop over an array of hexStrings like so: 这可以用来像这样循环遍历十六进制字符串数组:

var hexArray = ["2F", "24", "40", "2A"]
var charArray = [Character]()
charArray = map(hexArray) { charArray.append(Character($0)) }
charArray.description // prints -> "[/, $, @, *]"

A couple of things about your code: 有关代码的几件事:

var charArray = [Character]()
charArray = map(hexArray) { charArray.append(Character($0)) }

You don't need to create an array and then assign the result of the map, you can just assign the result and avoid creating an unnecessary array. 您无需先创建数组,然后分配地图结果,就可以分配结果,避免创建不必要的数组。

charArray = map(hexArray) { charArray.append(Character($0)) }

Here you can use hexArray.map instead of map(hexArray) , also when you use a map function what you are conceptually doing is mapping the elements of the receiver array to a new set of values and the result of the mapping is the new "mapped" array, which means that you don't need to do charArray.append inside the map closure. 在这里,您可以使用hexArray.map代替map(hexArray) ,同样,当您使用map函数时,您在概念上所做的就是将接收方数组的元素映射到一组新的值,并且映射的结果是新的“已映射”数组,这意味着您无需在地图闭包内部执行charArray.append

Anyway, here is a working example: 无论如何,这是一个有效的示例:

let hexArray = ["2F", "24", "40", "2A"]
var charArray = hexArray.map { char -> Character in
    let code = Int(strtoul(char, nil, 16))
    return Character(UnicodeScalar(code))
}
println(charArray) // -> [/, $, @, *]

EDIT: This is another implementation that doesn't need Foundation: 编辑:这是不需要基金会的另一个实现:

func hexToScalar(char: String) -> UnicodeScalar {
    var total = 0
    for scalar in char.uppercaseString.unicodeScalars {
        if !(scalar >= "A" && scalar <= "F" || scalar >= "0" && scalar <= "9") {
            assertionFailure("Input is wrong")
        }

        if scalar >= "A" {
            total = 16 * total + 10 + scalar.value - 65 /* 'A' */
        } else {
            total = 16 * total + scalar.value - 48 /* '0' */
        }
    }
    return UnicodeScalar(total)
}

let hexArray = ["2F", "24", "40", "2A"]
var charArray = hexArray.map { Character(hexToScalar($0)) }
println(charArray)

EDIT2 Yet another option: EDIT2另一个选择:

func hexToScalar(char: String) -> UnicodeScalar {
    let map = [ "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
        "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15 ]

    let total = reduce(char.uppercaseString.unicodeScalars, 0, { $0 * 16 + (map[String($1)] ?? 0xff) })
    if total > 0xFF {
        assertionFailure("Input char was wrong")
    }
    return UnicodeScalar(total)
}

Final edit: explanation 最终编辑:说明

Given that the ascii table has all the number together (012345679), we can convert 'N' (base 10) to an integer knowing the ascii value of 0. 假设ascii表具有所有数字(012345679),我们可以在知道ascii值为0的情况下将“ N”(以10为底)转换为整数。

Because: 因为:

'0': 48
'1': 49
...
'9': 57

Then if for example you need to convert '9' to 9 you could do 然后,例如,如果您需要将“ 9”转换为9,则可以这样做

asciiValue('9') - asciiValue('0') => 57 - 48 = 9

And you can do the same from 'A' to 'F': 您也可以从“ A”到“ F”执行相同的操作:

'A': 65
'B': 66
...
'F': 70

Now we can do the same as before but, for example for 'F' we'd do: 现在我们可以像以前一样做,但是例如对于“ F”,我们可以做:

asciiValue('F') - asciiValue('A') => 70 - 65 = 5

Note that we need to add 10 to this number to get the decimal. 请注意,我们需要在此数字上加10以获得小数。 Then (going back to the code): If the scalar is between AZ we need to do: 然后(返回代码):如果标量在AZ之间,我们需要这样做:

10 + asciiValue(<letter>) - asciiValue('A')

which is the same as: 10 + scalar.value - 65 等于: 10 + scalar.value - 65

And if it's between 0-9: 如果介于0到9之间:

asciiValue(<letter>) - asciiValue('0')

which is the same as: scalar.value - 48 scalar.value - 48相同

For example: '2F' 例如:“ 2F”

'2' is 2 and 'F' is 15 (by the previous example), right?. “ 2”是2,而“ F”是15(在前面的示例中),对吗? Since hex is base 16 we'd need to do: 由于十六进制是16的基数,我们需要这样做:

((16 ^ 1) * 2) + ((16 ^ 0) * 15) = 47

Here you go: 干得好:

var string = String(UnicodeScalar(Int("2C", radix: 16)!))

BTW, you can include hex values in the literal strings like this: 顺便说一句,您可以像这样在文字字符串中包含十六进制值:

var string = "\u{2c}"

With Swift 5, you will have to convert your string variable into an integer (using init(_:radix:) initializer), create Unicode scalar from this integer (using init(_:) ) then create a character from this Unicode scalar ( using init(_:) ). 使用Swift 5,您将必须将字符串变量转换为整数(使用init(_:radix:)初始化程序),从该整数创建Unicode标量(使用init(_:) ),然后根据此Unicode标量创建一个字符( using init(_:) )。

The Swift 5 Playground sample code below shows how to proceed: 下面的Swift 5 Playground示例代码显示了如何进行:

let validHexString: String = "2C"
let validUnicodeScalarValue = Int(validHexString, radix: 16)!
let validUnicodeScalar = Unicode.Scalar(validUnicodeScalarValue)!
let character = Character(validUnicodeScalar)
print(character) // prints: ","

If you want to perform this operation for the elements inside an array, you can use the sample code below: 如果要对数组中的元素执行此操作,则可以使用以下示例代码:

let hexArray = ["2F", "24", "40", "2A"]
let characterArray = hexArray.map({ (hexString) -> Character in
    let unicodeScalarValue = Int(hexString, radix: 16)!
    let validUnicodeScalar = Unicode.Scalar(unicodeScalarValue)!
    return Character(validUnicodeScalar)
})
print(characterArray) // prints: ["/", "$", "@", "*"]

Alternative with no force unwraps: 不用武力即可打开的替代方案:

let hexArray = ["2F", "24", "40", "2A"]
let characterArray = hexArray.compactMap({ (hexString) -> Character? in
    guard let unicodeScalarValue = Int(hexString, radix: 16),
        let unicodeScalar = Unicode.Scalar(unicodeScalarValue) else {
            return nil
    }
    return Character(unicodeScalar)
})
print(characterArray) // prints: ["/", "$", "@", "*"]

Another simple way based on ICU transforms: 另一种基于ICU转换的简单方法:

extension String {
  func transformingFromHex() -> String? {
    return "&#x\(self);".applyingTransform(.toXMLHex, reverse: true)
  }
}

Usage: 用法:

"2C".transformingFromHex()

Results in: , 结果: ,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM