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
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.
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.
size = 0
-> (DEFAULT) zero fill to the bit size of the containing typesize < 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
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)
)
}