【问题标题】:Hex String to Character in PURE SwiftPURE Swift 中的十六进制字符串到字符
【发布时间】:2015-04-08 16:12:39
【问题描述】:

我需要一种方法将包含表示十六进制值的文字字符串的字符串转换为对应于该特定十六进制值的字符。

理想情况下,遵循以下原则:

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

我尝试使用语法:“\u{n}”,其中 n 是 Int 或 String,但都不起作用。

这可以用来循环一个 hexStrings 数组,如下所示:

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

【问题讨论】:

    标签: swift unicode utf-8 hex character


    【解决方案1】:

    关于您的代码的几件事:

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

    您不需要创建数组然后分配映射的结果,您可以只分配结果,避免创建不必要的数组。

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

    在这里您可以使用hexArray.map 而不是map(hexArray),当您使用映射函数时,您在概念上所做的是将接收器数组的元素映射到一组新值,映射的结果是新的“映射”数组,这意味着您不需要在 map 闭包内执行 charArray.append

    无论如何,这是一个工作示例:

    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) // -> [/, $, @, *]
    

    编辑:这是另一个不需要 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 还有一个选择:

    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)
    }
    

    最终编辑:解释

    鉴于 ascii 表包含所有数字 (012345679),我们可以将 'N'(以 10 为底)转换为知道 ascii 值为 0 的整数。

    因为:

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

    然后,例如,如果您需要将“9”转换为 9,您可以这样做

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

    你可以从“A”到“F”做同样的事情:

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

    现在我们可以像以前一样做,但是,例如对于“F”,我们会这样做:

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

    请注意,我们需要在这个数字上加上 10 才能得到小数点。然后(回到代码):如果标量在 A-Z 之间,我们需要这样做:

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

    等同于:10 + scalar.value - 65

    如果它在 0-9 之间:

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

    等同于:scalar.value - 48

    例如:'2F'

    '2' 是 2 而 'F' 是 15(由前面的例子),对吧?由于十六进制是以 16 为基数,我们需要这样做:

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

    【讨论】:

    • 是的,我在地图和数组分配中看到了你的观点。至于使用在 Darwin 的 C 库中定义的 strtoul() 作为导入 Foundation 框架的一部分。我不能在这种情况下使用这个功能。不能使用 Foundation 框架中的任何函数。否则,代码有效。然而,这不是我要找的。​​span>
    • 好的,有一个问题:你的 hexArray 总是会被 ascii 编码吗? (如:没有超过 255 的字符)?
    • 是的,它们将/应该始终是 ASCII 字符
    • 刚刚添加了一个 hexToScalar 方法。
    • 我喜欢第一次编辑...我很好奇您是如何得出每个实例中总计的公式...这些是字符的十进制值吗?
    【解决方案2】:

    给你:

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

    顺便说一句,您可以像这样在文字字符串中包含十六进制值:

    var string = "\u{2c}"
    

    【讨论】:

      【解决方案3】:

      使用 Swift 5,您必须将字符串变量转换为整数(使用 init(_:radix:) 初始化程序),从该整数创建 Unicode 标量(使用 init(_:)),然后从该 Unicode 标量创建一个字符(using init(_:) )。

      下面的 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: ","
      

      如果要对数组中的元素执行此操作,可以使用下面的示例代码:

      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: ["/", "$", "@", "*"]
      

      没有强制展开的替代方案:

      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: ["/", "$", "@", "*"]
      

      【讨论】:

        【解决方案4】:

        另一种基于ICU变换的简单方法:

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

        用法:

        "2C".transformingFromHex()
        

        结果:,

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-04
          • 2014-03-07
          • 2021-08-11
          • 1970-01-01
          • 2016-02-26
          • 1970-01-01
          • 1970-01-01
          • 2017-03-04
          相关资源
          最近更新 更多