Как определить, установлен ли бит в шестнадцатеричной строке? - PullRequest
4 голосов
/ 05 февраля 2020

У меня есть строка в шестнадцатеричном формате, например:

AAE04471

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

10101010 11100000 01000100 01110001

Я пытаюсь определить, 32 бита установлены следующим образом:

 String s = "AAE04471";
 byte[] bytes = DatatypeConverter.parseHexBinary(s);
 System.out.println("Length bytes[] = " + bytes.length);
 BitSet bitset = BitSet.valueOf(bytes);
 System.out.println("Length of bitset = " + bitset.length());
 System.out.println("Look of bitset = " + bitset.toString());
 System.out.println("32 bit is " + bitset.get(31));

Я получаю «ложный» результат:

Length bytes[] = 4
Length of bitset = 31
Look of bitset = {1, 3, 5, 7, 13, 14, 15, 18, 22, 24, 28, 29, 30}
32 bit is false

Результат - совершенно другой и странный битовый порядок!

01010101 00000111 00100010 1000111

Что я делаю не так?

Как правильно определить, установлен ли бит в шестнадцатеричной строке?

Ответы [ 4 ]

2 голосов
/ 05 февраля 2020

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

public class Test {

    public static void main(String[] args) {
        for (int i = 0; i < 16; i++) {
            test("DEAD", i);
        }
    }

    public static boolean isBitSet(String hex, int bit) {
        int n = bit >> 2;
        int last = hex.length() - 1;
        if (n < 0 || n > last) return false;
        char c = hex.charAt(last - n);
        int v = Integer.parseInt(Character.toString(c), 16);
        int mask = 1 << (bit & 3);
        return (v & mask) != 0;
    }

    public static void test(String hex, int bit) {
        boolean set = isBitSet(hex, bit);
        System.out.format("%s, bit %2d, %s%n", hex, bit, set ? "set" : "not set");
    }

}

Вывод:

DEAD, bit  0, set
DEAD, bit  1, not set
DEAD, bit  2, set
DEAD, bit  3, set
DEAD, bit  4, not set
DEAD, bit  5, set
DEAD, bit  6, not set
DEAD, bit  7, set
DEAD, bit  8, not set
DEAD, bit  9, set
DEAD, bit 10, set
DEAD, bit 11, set
DEAD, bit 12, set
DEAD, bit 13, not set
DEAD, bit 14, set
DEAD, bit 15, set
1 голос
/ 06 февраля 2020

В этой реализации bitnr должно быть не менее 1. В основном одноиндексное. Я добавил небольшую ошибку, чтобы гарантировать, что bitnr остается в границах шестнадцатеричного числа.

Он находит точную 1-длину substring в вопросе и использует bitwise OR, чтобы определить, является ли конкретный бит установлен:

public class StackOverflowTest {
  public static void main(String[] args) {
    System.out.println(bitSet("AAE04471",1));          // true
    System.out.println(bitSet("AAE04471",17));         // false
    System.out.println(bitSet("AAE04471",32));         // true
    System.out.println(bitSet("AAE04471AAE04471",32)); // true
    System.out.println(bitSet("AAE04471AAE04471",40)); // false
    System.out.println(bitSet("AAE04471AAE04471",64)); // true
//    System.out.println(bitSet("AAE04471AAE04471",0));  // AssertionError
//    System.out.println(bitSet("AAE04471AAE04471",65)); // AssertionError
  }

  private static boolean bitSet(String hexString, int bitnr) {
    if (bitnr < 1 || hexString.length() * 4 < bitnr) {
      throw new AssertionError("bitnr is out of bounds");
    }

    // add 3 to the bitnr to make division by 4 go to correct index
    String bitString = hexString.substring(hexString.length()-(bitnr+3)/4,
                                           hexString.length()-(bitnr+3)/4+1);
    int check = Integer.parseInt(bitString,16);
    int OrInt = 1 << (bitnr + 3) % 4; // add 3 to the bitnr to make % 4 go to 3 for highest.
    return (check & OrInt) == OrInt;
  }
}
1 голос
/ 05 февраля 2020

Простой способ сделать это для больших шестнадцатеричных чисел заключается в следующем:

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        String hex = "AAE04471";
        System.out.println("Hexadecimal string: " + hex);

        BigInteger bigInt = new BigInteger(hex, 16);

        String binary = bigInt.toString(2);
        System.out.println("Binary string: " + binary);

        System.out.println("\nBit information:");
        System.out.println("32nd bit is " + (binary.charAt(binary.length() - 32) == '1' ? true : false));
        System.out.println("31st bit is " + (binary.charAt(binary.length() - 31) == '1' ? true : false));
        System.out.println("30th bit is " + (binary.charAt(binary.length() - 30) == '1' ? true : false));

        // Alternatively,
        System.out.println("\nBit information using an alternative method:");
        System.out.println("32nd bit is " + bigInt.testBit(31));
        System.out.println("31st bit is " + bigInt.testBit(30));
        System.out.println("30th bit is " + bigInt.testBit(29));
    }
}

Вывод:

Hexadecimal string: AAE04471
Binary string: 10101010111000000100010001110001

Bit information:
32nd bit is true
31st bit is false
30th bit is true

Bit information using an alternative method:
32nd bit is true
31st bit is false
30th bit is true

[ Обновление]

Теперь я разработал способ, который будет работать для шестнадцатеричного числа любой длины. Ниже приведено решение вместе с парой тестов:

public class Main {
    public static void main(String[] args) {
        String hex = "AAE04471";
        String binary = hexadecimalToBinary(hex);
        System.out.println("Hexadecimal: " + hex);
        System.out.println("Binary: " + binary);
        System.out.println("Is bit number 32 set: " + isBitSet(binary, 32));
        System.out.println("Is bit number 31 set: " + isBitSet(binary, 31));
        System.out.println("Is bit number 30 set: " + isBitSet(binary, 30));
        System.out.println("---------------------------------------------");        
        hex = "AAE044710C0000000000000000FF0000";
        binary = hexadecimalToBinary(hex);
        System.out.println("Hexadecimal: " + hex);
        System.out.println("Binary: " + binary);
        System.out.println("Is bit number 32 set: " + isBitSet(binary, 32));
        System.out.println("Is bit number 31 set: " + isBitSet(binary, 31));
        System.out.println("Is bit number 30 set: " + isBitSet(binary, 30));
    }

    static String hexadecimalToBinary(String hexadecimal) {
        String binary = hexadecimal;
        String[] hexDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
        String[] hextoBinaryDigits = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001",
                "1010", "1011", "1100", "1101", "1110", "1111" };
        for (int i = 0; i < hexDigits.length; i++)
            binary = binary.replaceAll(hexDigits[i], hextoBinaryDigits[i]);
        return binary;
    }

    static boolean isBitSet(String binary, int bitNumber) {
        if (bitNumber > binary.length()) {
            return false;
        }
        return binary.charAt(binary.length() - bitNumber) == '1' ? true : false;
    }
}

Вывод:

Hexadecimal: AAE04471
Binary: 10101010111000000100010001110001
Is bit number 32 set: true
Is bit number 31 set: false
Is bit number 30 set: true
---------------------------------------------
Hexadecimal: AAE044710C0000000000000000FF0000
Binary: 10101010111000000100010001110001000011000000000000000000000000000000000000000000000000000000000000000000111111110000000000000000
Is bit number 32 set: false
Is bit number 31 set: false
Is bit number 30 set: false

[2-е обновление]

Наконец, я разработал способ, который будет работать для шестнадцатеричного числа любой длины, и это тоже, без преобразования всего шестнадцатеричного числа в двоичное число. Скорее, этот метод преобразует только одну шестнадцатеричную ди git (шестнадцатеричная ди git, где находится номер бита, статус которого должен быть найден) в двоичную строку. Ниже приведено решение вместе с парой тестов:

public class Main {
    public static void main(String[] args) {
        String hex = "AAE04471";
        System.out.println("Hexadecimal: " + hex);
        System.out.println("Is bit number 32 set: " + isBitSet(hex, 32));
        System.out.println("Is bit number 31 set: " + isBitSet(hex, 31));
        System.out.println("Is bit number 30 set: " + isBitSet(hex, 30));
        System.out.println("----------------------");
        hex = "AAE044710C0000000000000000FF0000";
        System.out.println("Hexadecimal: " + hex);
        System.out.println("Is bit number 32 set: " + isBitSet(hex, 32));
        System.out.println("Is bit number 31 set: " + isBitSet(hex, 31));
        System.out.println("Is bit number 30 set: " + isBitSet(hex, 30));
    }

    static boolean isBitSet(String hex, int bitNumber) {
        if (bitNumber > hex.length() * 4) {
            return false;
        }
        int i = bitNumber % 4 == 0 ? bitNumber / 4 : bitNumber / 4 + 1;

        // Get the hexadecimal digit where lies the bit number whose status is to be
        // found.
        StringBuilder sb = new StringBuilder().append(hex.charAt(hex.length() - i));

        // Get the decimal equivalent of the hexadecimal digit
        int n = Integer.parseInt(sb.toString(), 16);

        // Convert the binary equivalent of the hexadecimal digit into 4-digit string by
        // left-padding 0
        String binaryStringIn4Digits = String.format("%1$" + 4 + "s", Integer.toBinaryString(n)).replace(' ', '0');

        return binaryStringIn4Digits.charAt(3 - bitNumber % 4) == '1' ? true : false;
    }
}

Вывод:

Hexadecimal: AAE04471
Is bit number 32 set: false
Is bit number 31 set: true
Is bit number 30 set: false
----------------------
Hexadecimal: AAE044710C0000000000000000FF0000
Is bit number 32 set: false
Is bit number 31 set: false
Is bit number 30 set: false

Надеюсь, все эти различные виды решений помогут вам решить вашу проблему.

0 голосов
/ 10 февраля 2020

Спасибо за ваши ответы.

Я хочу предложить свое решение на основе ваших советов (не самое оптимальное, но оно работает на 100%):

 private static boolean bitSet(String hexString, int bitPos)  {
        if (bitPos < 1) {
            throw new IllegalArgumentException("Bit position '" + bitPos + "' must be > 0");
        }
        if (hexString == null || hexString.trim().length() == 0 || hexString.trim().length() % 2 != 0) {
            throw new IllegalArgumentException("HEX string '" + hexString + "' is bad");
        }
        hexString = hexString.trim();

        StringBuilder bitString = new StringBuilder();

        for (int i = 0; i < hexString.length(); i += 2) {
            String byteStr = hexString.substring(i, i + 2);
        //    System.out.println("HEX byte '" +  byteStr + "'");
            String binary = new BigInteger(byteStr, 16).toString(2);
        //     System.out.println("binary '" +  binary + "'");
            if(binary.length() < 8 ) {
                binary = "00000000".substring(0, 8 - binary.length()) + binary;
            }
            bitString.append(binary);
        }

        System.out.println(bitString);

        if (bitString.length() < bitPos) {
            System.out.println(bitPos + "-nd bit is not contain in HEX  '" + hexString + "'");
            return false;
        }

        System.out.println(bitPos + "-nd bit is " + (bitString.charAt(bitPos - 1) == '1'));
        return bitString.charAt(bitPos - 1) == '1';
    }

Тесты:

    bitSet("0101", 8);
    bitSet("AAE04471", 32);
    bitSet("AAE044710C0000000000000000000000", 32);
    bitSet("AAE044710C000000000000000000000", 32);

Выходы:

0000000100000001
8-nd bit is true
10101010111000000100010001110001
32-nd bit is true
10101010111000000100010001110001000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
32-nd bit is true
Exception in thread "main" java.lang.IllegalArgumentException: HEX string 'AAE044710C000000000000000000000' is bad
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...