Java - анализировать и беззнаковую шестнадцатеричную строку в длинную со знаком

У меня есть куча шестнадцатеричных строк, например, одна из них:

  d1bc4f7154ac9edb

что является шестнадцатеричным значением "-3333702275990511909". Это тот же шестнадцатеричный код, который вы получите, если выполните Long.toHexString("d1bc4f7154ac9edb");

А пока предположим, что у меня есть доступ только к шестнадцатеричным строковым значениям, и все. Делая это:

  Long.parseLong(hexstring, 16);

Не работает, потому что преобразует его в другое значение, которое слишком велико для Long. Можно ли преобразовать эти беззнаковые шестнадцатеричные значения в длинные со знаком?

Спасибо!


person Peter    schedule 19.04.2011    source источник


Ответы (4)


Вы можете использовать BigInteger для анализа и получения назад long:

long value = new BigInteger("d1bc4f7154ac9edb", 16).longValue();
System.out.println(value); // this outputs -3333702275990511909
person WhiteFang34    schedule 19.04.2011
comment
Просто примечание для современных посетителей: как отмечает Скотт Кэри, начиная с Java 8 мы можем просто делать Long.parseUnsignedLong(hexstring, 16), так здорово :) - person NIA; 05.09.2017

Вы можете разделить его пополам и читать 32 бита за раз. Затем используйте сдвиг влево на 32 и логическое или, чтобы вернуть его в один длинный.

person Knut Forkalsrud    schedule 19.04.2011
comment
Примерно так: (Long.parseLong(hexstring.substring(0, 8), 16) ‹‹ 32) | (Long.parseLong(hexstring.substring(8, 16), 16) ‹‹ 0) - person Knut Forkalsrud; 10.06.2011

Преимущество приведенного ниже метода заключается в том, что он не создает еще один объект BigInteger каждый раз, когда вам нужно это сделать.

public class Test {
  /**
   * Returns a {@code long} containing the least-significant 64 bits of the unsigned hexadecimal input.
   * 
   * @param  valueInUnsignedHex     a {@link String} containing the value in unsigned hexadecimal notation
   * @return                        a {@code long} containing the least-significant 64 bits of the value
   * @throws NumberFormatException  if the input {@link String} is empty or contains any nonhexadecimal characters
   */
  public static final long fromUnsignedHex(final String valueInUnsignedHex) {
    long value = 0;

    final int hexLength = valueInUnsignedHex.length();
    if (hexLength == 0) throw new NumberFormatException("For input string: \"\"");
    for (int i = Math.max(0, hexLength - 16); i < hexLength; i++) {
      final char ch = valueInUnsignedHex.charAt(i);

      if      (ch >= '0' && ch <= '9') value = (value << 4) | (ch - '0'         );
      else if (ch >= 'A' && ch <= 'F') value = (value << 4) | (ch - ('A' - 0xaL));
      else if (ch >= 'a' && ch <= 'f') value = (value << 4) | (ch - ('a' - 0xaL));
      else                             throw new NumberFormatException("For input string: \"" + valueInUnsignedHex + "\"");
    }

    return value;
  }

  public static void main(String[] args) {
    System.out.println(fromUnsignedHex("d1bc4f7154ac9edb"));
  }
}

Это производит

-3333702275990511909
person Olathe    schedule 20.04.2011
comment
Это выглядит хорошо, но вместо получения цифровых значений, как вы делали выше, может быть, лучше использовать Character.digit? docs.oracle. com/javase/7/docs/api/java/lang/ - person asieira; 23.07.2014
comment
Character.digit включает в себя все десятичные цифры Unicode, и я не хочу обрабатывать их все, поскольку существует несколько их наборов, некоторые из которых должным образом не задокументированы. - person Olathe; 28.07.2014
comment
Я считаю, что возможность извлечь числовое значение любой из возможных цифр Unicode является плюсом, поскольку делает ваш код более переносимым и удобным для интернационализации. Даже если вашему проекту это не нужно, возможно, пользователи переполнения стека выиграют, если вы обновите свой ответ. Просто мои 2 цента. - person asieira; 29.07.2014

Предыдущие ответы слишком сложны или устарели.

Long.parseUnsignedLong(hexstring, 16)

person Scott Carey    schedule 13.03.2017