Scala:如何正确解析 0~FFFF 范围内的十六进制值,确保我总是以 16 位结束,因为每一位都有自己的价值?

Scala: how to parse Hexadecimal value in range 0~FFFF correctly, making sure I always end up with 16 bits, as each bit brings value on its own?

我需要解码包含十六进制值的字符串。

十六进制值需要解码为16位,每一位都有自己的含义。

我尝试使用以下代码,但它是错误的,一旦十六进制值被解码,似乎并不总是 16 位。

我花了很多时间试图解决这个问题,但没能成功,如果有人能帮助我,我将不胜感激。

谢谢!

Here are some Hex examples:
A42
800   
242
0
2
4000

> val stat = BigInt(hexVal, 16).toString(2)
> for (s <- stat.indices) {
>      s match {
>        case 0 => bit1 = stat.substring(s, s+1) 
>        case 1 => bit2 = stat.substring(s, s+1)
>        case 2 => bit3 = stat.substring(s, s+1)
>        case 3 => bit4 = stat.substring(s, s+1)
>        case 4 => bit5 = stat.substring(s, s+1)
>        case 5 => bit6 = stat.substring(s, s+1)
>        case 6 => bit7  = stat.substring(s, s+1) 
>        case 7 => bit8 = stat.substring(s, s+1)
>        case 8 => bit9 = stat.substring(s, s+1) 
>        case 9 => bit10 = stat.substring(s, s+1) 
>        case 10 => bit11  = stat.substring(s, s+1) 
>        case 11 => bit12 = stat.substring(s, s+1) 
>        case 12 => bit13 = stat.substring(s, s+1)
>        case 13 => bit14  = stat.substring(s, s+1)
>        case 14 => bit15 = stat.substring(s, s+1)
>        case 15 => bit16 = stat.substring(s, s+1)
>      }

您可以在剩余的缺失数字前加上零以获得完整的 16 位数字。

val bit = BigInt(hexVal, 16).toString(2)
val result = "0" * (16 -bit.length()) + bit

一种选择是使用 f 格式的字符串插值:

val v = BigInt(BigInt(hexVal, 16).toString(2), 10)

val stat = f"$v%016d"

请不要在未检查 hexVal 字符串长度的情况下使用 BigInt 解析不受信任的输入。因为即使是 16 进制,它也具有 O(n^2) 的复杂性,并且可以使您的系统容易受到 DoS/DoW 攻击。

Bellow 是将十六进制字符串解析为 Short(16 位)值的代码。它对任何输入都能高效安全地工作:

$ scala
Welcome to Scala 2.13.0 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions for evaluation. Or try :help.

scala> :paste
// Entering paste mode (ctrl-D to finish)

  def hexStringToShort(s: String): Short =
    if (s.length > 4) sys.error(s"too long hex string: $s")
    else {
      var v = 0
      var i = 0
      while (i < s.length) {
        v = (v << 4) + hexCharToNibble(s.charAt(i))
        i += 1
      }
      v.toShort
    }

  def hexCharToNibble(ch: Char): Int =
    if (ch >= '0' && ch <= '9') ch - 48
    else {
      val b = ch & -33
      if (b >= 'A' && b <= 'F') b - 55
      else sys.error(s"illegal hex char: $ch")
    }

// Exiting paste mode, now interpreting.

hexStringToShort: (s: String)Short
hexCharToNibble: (ch: Char)Int

scala> hexStringToShort("A42")
res0: Short = 2626

scala> hexStringToShort("A42").toHexString
res1: String = a42

scala> hexStringToShort("4000").toHexString
res2: String = 4000

要测试位,您可以使用以下函数:

scala> def hasBit(v: Short, b: Int): Boolean = b < 16 && b >= 0 && (v & (1 << b)) != 0
hasBit: (v: Short, b: Int)Boolean

scala> hasBit(hexStringToShort("4000"), 2)
res3: Boolean = false

scala> hasBit(hexStringToShort("4000"), 14)
res4: Boolean = true

scala> hasBit(hexStringToShort("4000"), 15)
res5: Boolean = false