Форматирование двоичных значений в Scala - PullRequest
31 голосов
/ 25 февраля 2012

Есть ли в Scala встроенный форматер для двоичных данных?

Например, распечатать: 00000011 для значения Int 3.

Написание одного не составит труда - просто любопытно, если оно существует.

Ответы [ 8 ]

61 голосов
/ 25 февраля 2012
scala> 3.toBinaryString
res0: String = 11

Scala имеет неявное преобразование из Int в RichInt, у которого есть метод toBinaryString. Однако эта функция не печатает начальные нули.

20 голосов
/ 25 февраля 2012

Я не знаю прямого метода API для этого, но вот один из способов сделать это:

def toBinary(i: Int, digits: Int = 8) =
    String.format("%" + digits + "s", i.toBinaryString).replace(' ', '0')
10 голосов
/ 25 февраля 2012

8 цифр для числа 3 с ведущими нулями:

printf ("%08d", 3.toBinaryString.toInt)
00000011

Так как Хосам Али предлагает также создать строку, вот метод для этого:

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?

3 голосов
/ 28 сентября 2017

Я обычно использую для добавления нулей желаемой длины -1, а затем просто нарезаю крайние правые символы:

"0000000" + 3.toBinaryString takeRight 8

Это прекрасно работает и для отрицательных значений.

3 голосов
/ 25 февраля 2012

Вот еще один способ (старая Java):

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

Так же, как ответ Лаури, он не печатает начальные нули.

2 голосов
/ 01 марта 2019

Встроенные в стандартную библиотеку Scala двоичные цифры String форматеры (toBinaryString) для целочисленных типов (Byte, Short, Char, Int и Long)очень ограничены.И реализация для Boolean не предусмотрена.

Кроме того, для Byte и Short фактический выданный формат неверен для отрицательных значений (так как оба варианта реализации Int.toBinaryString, которые затем1 заполняет до 32 символов, а не правильной ширины 8 и 16 символов соответственно.

Кроме того, я прочитал каждый ответ здесь.И я довольно много узнал о различных подходах к решению этой проблемы.В конечном счете, не было ни капли в решении, которое «просто работало» в моем текущем проекте.Итак ...

Я создал единую реализацию метода, исправляя, а затем исправляя все вышеперечисленные несоответствия, ошибки и добавляя недостающие функциональные возможности.Теперь, если бы я только мог понять, как включить это в стандартную библиотеку для 2.13 и Scala 3 ...

Параметр size имеет три области значений.Более подробные сведения см. В комментариях к коду.

  1. size = 0 -> (ПО УМОЛЧАНИЮ) заполнение нулями до размера в битах содержащего типа
  2. size < 0 -> модель по умолчаниюповедение функции toBinaryString уже на Byte, Short, Char, Int и Long - также исправьте скрытое повышение в Int для Byte и Short
  3. 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)
      )
    }
1 голос
/ 20 ноября 2013

Это напечатает ведущие нули:

  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)
  }
0 голосов
/ 25 февраля 2012

Вы можете сделать что-то вроде этого:

scala> val x = 3
x: Int = 3

scala> Integer.toString(x, 2)
res4: java.lang.String = 11

Как и в других предложениях, здесь нет ведущих нулей ...

...