Format byte as a two character hex number - java

I would like to format byte as a two character hex number. In C# you would do this:
string.Format("{0:X2}", recvBuff[indx])
How do you do the same thing in Java?

The toString-method of Integer and Long can take a base, up to 36 afaik, so you would pick 16:
String hex = Integer.toString (recvBuff[indx], 16);

Since your question asks for a "two character", you will have to make sure values are not greater than 256 (otherwise will print 3 hex digits or more). You also need to pad with zero if values less than 16.
public class HexTwoChars
{
static public void main(String[] args)
{
int values[] = { 1, 100, 10000 };
for (int v: values)
System.out.println( String.format("%02x", v % 256 ));
}
}
Running this program prints
01
64
10

Related

Converting a hexadecimal string to integer value without pre-made syntax

I'm taking a computer organization class in college. I was tasked with writing a java program that takes a user-inputted string, calls a function that converts said string into a hexadecimal integer, and then outputs the results.
The kicker is that I can't use any existing syntax to do this. for example, Integer.parseInt(__,16) or printf. It all neds to be hardcoded.
Now I'm not asking you to do my homework for me, just wanting to be put in the right direction.
So far, I've made this but can't seem to get the method created right:
import java.util.*;
public class Demo_Class
{
public static void main(String[] args)
{
Scanner AI = new Scanner(System.in);
String str;
System.out.println("Please input a hexadecimal number: ");
str = AI.nextLine();
converter(str);
}
public static int converter(String in)
{
String New = new String();
for(int i = 0; i<= in.length(); i++)
{
New += in.charAt(i);
System.out.println(New + 316);
}
return 0;
}
}
Consider this, lets says you have the hex value 1EC which in hex digits would be 1, E, C. In decimal they would be 1, 14, 12.
so set sum = 0.
sum = sum*16 + 1. sum is now 1
sum = sum*16 + 14 sum is now 30
sum = sum*16 + 12 sum is now 492
So 492 is the answer.
If you have a string of 1EC you need to convert to characters and then convert those characters to the decimal equivalent of hex values.
Try this on paper until you get the feel and then code it. You can check your results using the Integer method you mentioned.
#WJS gave a good hint, I'd just like to add that the charAt() returns the char, which is encoded in ASCII.
As you can see in the ASCII table, the characters A-F have decimal values from 65 to 70, while 0-9 go from 48 to 57 so you'll need to use them to convert the ASCII characters to their intended value.
To do so, you can either get the decimal value of a character by casting to short like short dec = (short)in.charAt(i);, or directly use the characters like char current = in.charAt(i) - 'A'.
With this in mind, all that's left is some calculation, I'll leave that as the homework. :)
Also:
you are looping one character more than needed, change the i <= in.length() to i < in.length(), since it's going from 0
I don't know what that 316 "magic number" is, if it does mean something, declare a variable with a meaningful name, like:
final int MEANINGFUL_NAME = 316;

US-ASCII string (de-)compression into/from a byte array (7 bits/character)

As we all know, ASCII uses 7-bit to encode chars, so number of bytes used to represent the text is always less than the length of text letters
For example:
StringBuilder text = new StringBuilder();
IntStream.range(0, 160).forEach(x -> text.append("a")); // generate 160 text
int letters = text.length();
int bytes = text.toString().getBytes(StandardCharsets.US_ASCII).length;
System.out.println(letters); // expected 160, actual 160
System.out.println(bytes); // expected 140, actual 160
Always letters = bytes, but the expected is letters > bytes.
the main proplem: in smpp protocol sms body must be <= 140 byte, if we used ascii encoding, then you can write 160 letters =(140*8/7),so i'd like to text encoded in 7-bit based ascii, we are using JSMPP library
Can anyone explain it to me please and guide me to the right way, Thanks in advance (:
(160*7-160*8)/8 = 20, so you expect 20 bytes less used by the end of your script. However, there is a minimum size for registers, so even if you don't use all of your bits, you still can't concat it to an another value, so you are still using 8 bit bytes for your ASCII codes, that's why you get the same number. For example, the lowercase "a" is 97 in ASCII
‭01100001‬
Note the leading zero is still there, even it is not used. You can't just use it to store part of an another value.
Which concludes, in pure ASCII letters must always equal bytes.
(Or imagine putting size 7 object into size 8 boxes. You can't hack the objects to pieces, so the number of boxes must equal the number of objects - at least in this case.)
Here is a quick & dirty solution without any libraries, i.e. only JRE on-board means. It is not optimised for efficiency and does not check if the message is indeed US-ASCII, it just assumes it. It is just a proof of concept:
package de.scrum_master.stackoverflow;
import java.util.BitSet;
public class ASCIIConverter {
public byte[] compress(String message) {
BitSet bits = new BitSet(message.length() * 7);
int currentBit = 0;
for (char character : message.toCharArray()) {
for (int bitInCharacter = 0; bitInCharacter < 7; bitInCharacter++) {
if ((character & 1 << bitInCharacter) > 0)
bits.set(currentBit);
currentBit++;
}
}
return bits.toByteArray();
}
public String decompress(byte[] compressedMessage) {
BitSet bits = BitSet.valueOf(compressedMessage);
int numBits = 8 * compressedMessage.length - compressedMessage.length % 7;
StringBuilder decompressedMessage = new StringBuilder(numBits / 7);
for (int currentBit = 0; currentBit < numBits; currentBit += 7) {
char character = (char) bits.get(currentBit, currentBit + 7).toByteArray()[0];
decompressedMessage.append(character);
}
return decompressedMessage.toString();
}
public static void main(String[] args) {
String[] messages = {
"Hello world!",
"This is my message.\n\tAnd this is indented!",
" !\"#$%&'()*+,-./0123456789:;<=>?\n"
+ "#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n"
+ "`abcdefghijklmnopqrstuvwxyz{|}~",
"1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
};
ASCIIConverter asciiConverter = new ASCIIConverter();
for (String message : messages) {
System.out.println(message);
System.out.println("--------------------------------");
byte[] compressedMessage = asciiConverter.compress(message);
System.out.println("Number of ASCII characters = " + message.length());
System.out.println("Number of compressed bytes = " + compressedMessage.length);
System.out.println("--------------------------------");
System.out.println(asciiConverter.decompress(compressedMessage));
System.out.println("\n");
}
}
}
The console log looks like this:
Hello world!
--------------------------------
Number of ASCII characters = 12
Number of compressed bytes = 11
--------------------------------
Hello world!
This is my message.
And this is indented!
--------------------------------
Number of ASCII characters = 42
Number of compressed bytes = 37
--------------------------------
This is my message.
And this is indented!
!"#$%&'()*+,-./0123456789:;<=>?
#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
--------------------------------
Number of ASCII characters = 97
Number of compressed bytes = 85
--------------------------------
!"#$%&'()*+,-./0123456789:;<=>?
#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
--------------------------------
Number of ASCII characters = 160
Number of compressed bytes = 140
--------------------------------
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Based on the encoding type, Byte length would be different. Check the below example.
String text = "0123456789";
byte[] b1 = text.getBytes(StandardCharsets.US_ASCII);
System.out.println(b1.length);
// prints "10"
byte[] utf8 = text.getBytes(StandardCharsets.UTF_8);
System.out.println(utf8.length);
// prints "10"
byte[] utf16= text.getBytes(StandardCharsets.UTF_16);
System.out.println(utf16.length);
// prints "22"
byte[] utf32 = text.getBytes(StandardCharsets.ISO_8859_1);
System.out.println(utf32.length);
// prints "10"
Nope. In "modern" environments (since 3 or 4 decades ago), the ASCII character encoding for the ASCII character set uses 8 bit code units which are then serialized to one byte each. This is because we want to move and store data in "octets" (8-bit bytes). This character encoding happens to always have the high bit set to 0.
You could say there was, used long ago, a 7-bit character encoding for the ASCII character set. Even then data might have been moved or stored as octets. The high bit would be used for some application-specific purpose such as parity. Some systems, would zero it out in an attempt to increase interoperability but in the end hindered interoperability by not being "8-bit safe". With strong Internet standards, such systems are almost all in the past.

java - Enforce 4 digit hex representation of a binary number

Below is a snippet of my java code.
//converts a binary string to hexadecimal
public static String binaryToHex (String binaryNumber)
{
BigInteger temp = new BigInteger(binaryNumber, 2);
return temp.toString(16).toUpperCase();
}
If I input "0000 1001 0101 0111" (without the spaces) as my String binaryNumber, the return value is 957. But ideally what I want is 0957 instead of just 957. How do I make sure to pad with zeroes if hex number is not 4 digits?
Thanks.
You do one of the following:
Manually pad with zeroes
Use String.format()
Manually pad with zeroes
Since you want extra leading zeroes when shorter than 4 digits, use this:
BigInteger temp = new BigInteger(binaryNumber, 2);
String hex = temp.toString(16).toUpperCase();
if (hex.length() < 4)
hex = "000".substring(hex.length() - 1) + hex;
return hex;
Use String.format()
BigInteger temp = new BigInteger(binaryNumber, 2);
return String.format("%04X", temp);
Note, if you're only expecting the value to be 4 hex digits long, then a regular int can hold the value. No need to use BigInteger.
In Java 8, do it by parsing the binary input as an unsigned number:
int temp = Integer.parseUnsignedInt(binaryNumber, 2);
return String.format("%04X", temp);
The BigInteger becomes an internal machine representation of whatever value you passed in as a String in binary format. Therefore, the machine does not know how many leading zeros you would like in the output format. Unfortunately, the method toString in BigInteger does not allow any kind of formatting, so you would have to do it manually if you attempt to use the code you showed.
I customized your code a bit to include leading zeros based on input string:
public static void main(String[] args) {
System.out.println(binaryToHex("0000100101010111"));
}
public static String binaryToHex(String binaryNumber) {
BigInteger temp = new BigInteger(binaryNumber, 2);
String hexStr = temp.toString(16).toUpperCase();
int b16inLen = binaryNumber.length()/4;
int b16outLen = hexStr.length();
int b16padding = b16inLen - b16outLen;
for (int i=0; i<b16padding; i++) {
hexStr=('0'+hexStr);
}
return hexStr;
}
Notice that the above solution counts up the base16 digits in the input and calculates the difference with the base16 digits in the output. So, it requires the user to input a full '0000' to be counted up. That is '000 1111' will be displayed as 'F' while '0000 1111' as '0F'.

Long to hex String number of characters

Hi i am trying to build a random 16 characters hex, to do so i tried a Long.toHexString(new Random().nextLong() my assumption is that it will always return a 16 chars string, Am i right ? (Once it returned 15 chars)
Take a look at the javadocs for toHexString(long i) (emphasis mine).
public static String toHexString(long i)
Returns a string
representation of the long argument as an unsigned integer in base 16.
The unsigned long value is the argument plus 264 if the argument is
negative; otherwise, it is equal to the argument. This value is
converted to a string of ASCII digits in hexadecimal (base 16) with no
extra leading 0s. If the unsigned magnitude is zero, it is represented
by a single zero character '0' ('\u0030'); otherwise, the first
character of the representation of the unsigned magnitude will not be
the zero character.
As it turns out, it will not always be 16 characters long. However you can pad with zeros if you want like so:
import java.util.Random;
class Main {
public static void main(String[] args) {
String hex16Chars = String.format("%016X", new Random().nextLong());
System.out.println(hex16Chars + ", len: " + hex16Chars.length());
}
}
You will see the length is always 16 as expected.
And it also turns out peeking at the docs actually helps! :)
Referring to Javadoc of the method in question should be your first port of call:
This value is converted to a string of ASCII digits in hexadecimal (base 16) with no extra leading 0s
So no, it won't always be 16 chars.
However, you can print a 16-char uppercased hex string, with leading zeros, using:
String.format("%016X", longValue)

Hash a String into fixed bit hash value

I want to hash a word into fixed bit hash value say 64 bit,32 bit (binary).
I used the following code
long murmur_hash= MurmurHash.hash64(word);
Then murmur_hash value is converted into binary by the following function
public static String intToBinary (int n, int numOfBits) {
String binary = "";
for(int i = 0; i < numOfBits; ++i) {
n/=2;
if(n%2 == 0)
{
binary="0"+binary;
}
else
binary="1"+binary;
}
return binary;
}
Is there any direct hash method to convert into binary?
Just use this
Integer.toBinaryString(int i)
If you want to convert into a fixed binary string, that is, always get a 64-character long string with zero padding, then you have a couple of options. If you have Apache's StringUtils, you can use:
StringUtils.leftPad( Long.toBinaryString(murmurHash), Long.SIZE, "0" );
If you don't, you can write a padding method yourself:
public static String paddedBinaryFromLong( long val ) {
StringBuilder sb = new StringBuilder( Long.toBinaryString(val));
char[] zeros = new char[Long.SIZE - sb.length()];
Arrays.fill(zeros, '0');
sb.insert(0, zeros);
return sb.toString();
}
This method starts by using the Long.toBinaryString(long) method, which conveniently does the bit conversion for you. The only thing it doesn't do is pad on the left if the value is shorter than 64 characters.
The next step is to create an array of 0 characters with the missing zeros needed to pad to the left.
Finally, we insert that array of zeros at the beginning of our StringBuilder, and we have a 64-character, zero-padded bit string.
Note: there is a difference between using Long.toBinaryString(long) and Long.toString(long,radix). The difference is in negative numbers. In the first, you'll get the full, two's complement value of the number. In the second, you'll get the number with a minus sign:
System.out.println(Long.toString(-15L,2));
result:
-1111
System.out.println(Long.toBinaryString(-15L));
result:
1111111111111111111111111111111111111111111111111111111111110001
Another other way is using
Integer.toString(i, radix)
you can get string representation of the first argument i in the radix ( Binary - 2, Octal - 8, Decimal - 10, Hex - 16) specified by the second argument.

Categories