Имеет ли Scala встроенный форматтер для двоичных данных?
Например, для печати: 00000011 для значения Int.
Написание одного не составит труда - просто любопытно, существует ли он.
Имеет ли Scala встроенный форматтер для двоичных данных?
Например, для печати: 00000011 для значения Int.
Написание одного не составит труда - просто любопытно, существует ли он.
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')
8 цифр для числа 3 с ведущими нулями:
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)
Как и Лаури, он не печатает ведущие нули.
Обычно я использую для добавления нулей требуемой длины -1, а затем просто нарезать самые правые символы:
"0000000" + 3.toBinaryString takeRight 8
Это отлично работает и для отрицательных значений.
Стандартные библиотеки Scala, встроенные в двоичные цифры Форматировщики String
(toBinaryString
) для целочисленных типов (Byte
, Short
, Char
, Int
и Long
) очень ограничены. И реализация для Boolean
не предусмотрена.
Кроме того, для Byte
и Short
Int.toBinaryString
фактический формат Int.toBinaryString
является неправильным для отрицательных значений (так как оба пересылаются в реализацию Int.toBinaryString
которая затем 1
заполняет до 32 символов, а не правильную ширину 8 и 16 символов соответственно).
Кроме того, я прочитал каждый ответ здесь. И я довольно много узнал о различных подходах к решению этой проблемы. В конечном счете, не было ни капли в решении, которое "просто работало" в моем текущем проекте. Так...
Я создал исправление реализации одного метода, а затем исправил все вышеперечисленные несоответствия, ошибки и добавил недостающую функциональность. Теперь, если бы я только мог понять, как включить это в стандартную библиотеку для 2.13 и Scala 3...
Параметр size
имеет три домена значений. Смотрите комментарии к коду для более точных деталей.
size = 0
→ (DEFAULT) заполнение нулями до размера в битах содержащего типаsize < 0
→ модель поведения по умолчанию функции toBinaryString уже на Byte
, Short
, Char
, Int
и Long
- также зафиксировать скрытые вентиляционный для 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
Как и в других предложениях, у этого нет начальных нулей...