在Scala中格式化二进制值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Scala中格式化二进制值相关的知识,希望对你有一定的参考价值。
Scala是否有内置的二进制数据格式化程序?
例如,打印输出:00000011表示Int值3。
写一个并不难 - 只是好奇它是否存在。
scala> 3.toBinaryString
res0: String = 11
Scala有一个从Int到RichInt的隐式转换,它有一个方法toBinaryString。此功能不会打印前导零。
我不知道直接的API方法,但这是一种方法:
def toBinary(i: Int, digits: Int = 8) =
String.format("%" + digits + "s", i.toBinaryString).replace(' ', '0')
带有前导零的数字3的8位数字:
printf ("%08d", 3.toBinaryString.toInt)
00000011
由于Hosam Aly建议也创建一个String,这里有一个方法:
def asNdigitBinary (source: Int, digits: Int): String = {
val l: java.lang.Long = source.toBinaryString.toLong
String.format ("%0" + digits + "d", l) }
在一般情况下,使用Long更合适,因为二进制值变得非常快:
scala> asNdigitBinary (1024*512-1, 32)
res23: String = 00000000000001111111111111111111
所以记住这一点 - 一个自制的,递归的方法,逐个数字生成并最终填充它们很容易处理BigInt的任意值。
def toBinDigits (bi: BigInt): String = {
if (bi == 0) "0" else toBinDigits (bi /2) + (bi % 2)}
def fillBinary (bi: BigInt, len: Int) = {
val s = toBinDigits (bi)
if (s.length >= len) s
else (List.fill (len-s.length) ("0")).mkString ("") + s
}
如果,那会很好
def asNdigitBinary (source: Int, digits: Int): String = {
val l = BigInt (source.toBinaryString.toLong)
String.format ("%0" + digits + "d", l)}
会工作,但“%0Nd”与BigInt数字不匹配。也许应该提出Bugreport / Feature请求?但是对于Scala还是Java?
这是另一种方式(旧Java):
val x = 5
val str = Integer.toString(x,2)
就像Lauri的回答一样,它不会打印前导零。
我通常使用前置所需长度为-1的零,然后只删除最右边的字符:
"0000000" + 3.toBinaryString takeRight 8
这也适用于负值。
Scala标准库的内置二进制数字String
格式化程序(toBinaryString
)用于整数类型(Byte
,Short
,Char
,Int
和Long
)非常有限。并没有提供Boolean
的实现。
另外,对于Byte
和Short
,实际发出的格式对于负值是错误的(因为向前到Int.toBinaryString
实现,然后1
填充到32个字符,而不是正确的宽度分别为8和16个字符)。
另外,我已经阅读了这里的每个答案。我学到了很多关于解决这个问题的各种方法。但最终,在我当前的项目中,“正常工作”的解决方案没有下降。所以...
我创建了一个单一的方法实现修复,然后增强了所有上述不一致,错误,并添加了缺少的功能。现在,如果我只能弄清楚如何将它包含在标准库2.13和Scala 3中......
size
参数有三个值域。有关更多详细信息,请参阅代码注释。
size = 0
- >(DEFAULT)零填充到包含类型的位大小size < 0
- >模拟已经在Byte
,Short
,Char
,Int
和Long
上的toBinaryString函数的默认行为 - 也为Int
和Byte
修复了Short
的隐藏向上size > 0
- >调用者指定零填充 - 如果大小小于捕获最左边的1
数字左侧的0
数字所需的长度(以保留符号),则忽略
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)
)
}
这将打印前导零:
def int2bin(i: Int, numPos: Int): String = {
def nextPow2(i: Int, acc: Int): Int = if (i < acc) acc else nextPow2(i, 2 * acc)
(nextPow2(i, math.pow(2,numPos).toInt)+i).toBinaryString.substring(1)
}
你可以这样做:
scala> val x = 3
x: Int = 3
scala> Integer.toString(x, 2)
res4: java.lang.String = 11
与其他建议一样,这没有前导零...
以上是关于在Scala中格式化二进制值的主要内容,如果未能解决你的问题,请参考以下文章
Golang PrintfSprintf Fprintf 格式化