Formatting binary values in Scala

前端 未结 8 940
伪装坚强ぢ
伪装坚强ぢ 2020-12-08 19:15

Does Scala have a built in formatter for binary data?

For example to print out: 00000011 for the Int value 3.

Writing one won\'t be difficult - just curious

相关标签:
8条回答
  • 2020-12-08 20:06

    Here is one more way (old Java):

    val x = 5
    val str = Integer.toString(x,2)
    

    Just like Lauri answer, it doesn't print leading zeros.

    0 讨论(0)
  • 2020-12-08 20:07

    The Scala standard library's built-in to-binary-digits String formatters (toBinaryString) for the integer types (Byte, Short, Char, Int, and Long) are very limited. And an implementation for Boolean isn't provided.

    Additionally, for Byte and Short, the actual emitted format is wrong for negative values (as both forward to the Int.toBinaryString implementation which then 1 fills out to 32 characters, not the correct widths of 8 and 16 characters respectively).

    Also, I have read through every answer here. And I learned quite a bit about the various ways to approach solving this problem. Ultimately, though, there wasn't a drop in solution which "just worked" within my current project. So...

    I have created a single method implementation fixing and then enhancing all of the above inconsistencies, errors, and adds missing functionality. Now, if I could only figure out how to get this included in the Standard Library for 2.13 and Scala 3...

    The size parameter has three domains of values. See the code comments for more precise details.

    1. size = 0 -> (DEFAULT) zero fill to the bit size of the containing type
    2. size < 0 -> model the default behavior of toBinaryString function already on Byte, Short, Char, Int, and Long - also fix the hidden upcast to Int for both Byte and Short
    3. size > 0 -> caller designated zero fill - ignored if the size is smaller than the length required to capture the 1 digit immediately to the left of the leftmost 0 digit (to preserve the sign)

        def toBinaryString[A <: AnyVal](value: A, size: Int = 0): String = {
          val zerosX64: String = //maximum possible number of leading zeros
            "0" * 64
    
          val (valueAsBinaryString, typeSize) =
            value match {
              case valueAlmostTyped: Boolean =>
                (if (valueAlmostTyped) "1" else "0", 1)
              case valueAlmostTyped: Byte =>
                (valueAlmostTyped.toByte.toBinaryString.takeRight(8), 8) //take() fixes hidden upcast to Int in Byte.toBinaryString
              case valueAlmostTyped: Short =>
                (valueAlmostTyped.toShort.toBinaryString.takeRight(16), 16) //take() fixes hidden upcast to Int in Short.toBinaryString
              case valueAlmostTyped: Char =>
                (valueAlmostTyped.toChar.toBinaryString, 16)
              case valueAlmostTyped: Int =>
                (valueAlmostTyped.toInt.toBinaryString, 32)
              case valueAlmostTyped: Long =>
                (valueAlmostTyped.toLong.toBinaryString, 64)
              case _ =>
                throw new IllegalArgumentException(s"toBinaryString not implemented for this type [${value.getClass.getSimpleName}] - only implemented for Boolean, Byte, Short, Char, Int, and Long")
            }
    
          val newSize =
            if (size < 0) //model and fix the behavior of existing toBinaryString function on Byte, Short, Char, Int, and Long, and add for Binary
              valueAsBinaryString.length
            else
              if (size == 0) //zero fill to the bit size of the containing type
                typeSize
              else
                if (valueAsBinaryString.length > size) //possibly override the caller specified custom size value as it is smaller than the resulting valueAsBinaryString itself
                  if (valueAsBinaryString.take(valueAsBinaryString.length - size + 1).exists(_ == '0')) //only override if there isn't a zero dropped (which includes protecting the sign by ensuring if all 1s preceded the 0, at least a single one is preserved
                    valueAsBinaryString.length
                  else //caller specified custom value
                    size
                else //caller specified custom value
                  size
          ( (
                if (newSize > valueAsBinaryString.length)
                  zerosX64.take(newSize - valueAsBinaryString.length)
                else
                  ""
            )
            + valueAsBinaryString.takeRight(newSize)
          )
        }
    
    0 讨论(0)
提交回复
热议问题