I have a byte array and I have to print it in a textview, in two differents format :
hex string
decimal string
For hex string I use this function (found on stackoverflow) :
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
while to convert byte array to decimal string I use this :
BigInteger bi = new BigInteger(value);
// Format to decimal
String s = bi.toString();
For the byte to hex conversion I am secure that it works correctly, but for the byte-to-decimal string conversion I am no much secure..
Are there better methods ?
EDIT : my desidered output is a decimal value for each byte
This will print out the byte array as decimals, with leading zeros (as your hex output does) and a space after each number:
final protected static char[] decimalArray = "0123456789".toCharArray();
public static String bytesToDecimal(byte[] bytes) {
char[] decimalChars = new char[bytes.length * 4];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
decimalChars[j * 4] = decimalArray[v / 100];
decimalChars[j * 4 + 1] = decimalArray[(v / 10) % 10];
decimalChars[j * 4 + 2] = decimalArray[v % 10];
decimalChars[j * 4 + 3] = ' ';
}
return new String(decimalChars);
}
I've changed the base from 16 to 10, increased the maximum number of characters from 2 to 3 corresponding to max values of FF for base 16 and 255 for decimal. Modulo 10 is used instead of a binary bitmask for masking individual digits because bitmasks only work with powers of 2 like 16.
Related
I have string and there is 0x80 in it. string presentation is : serialno� and hex presentation is 73 65 72 69 61 6C 6E 6F 80. I want to remove 0x80 from string without convert string to hex string. is it possible in java ? I tried lastIndexOf(0x80). but it returns -1.
my code is (also you can find on https://ideone.com/3p8wKT) :
public static void main(String[] args) {
String hexValue = "73657269616C6E6F80";
String binValue = hexStringToBin(hexValue);
System.out.println("binValue : " + binValue);
int index = binValue.lastIndexOf(0x80);
System.out.println("index : " + index);
}
public static String hexStringToBin(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return new String(data);
}
Change your hex string method to map directly to characters.
char[] data = new char[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (char) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return new String(data);
The exchange between a String and byte[] requires an encoding.
Your hex string seems to be a string representation of bytes/characters. It would appear you had an original String -> converted it to your hex string, but we don't know the encoding.
If you want to say that each pair of characters maps to the corresponding character, eg "80" -> char c = 0x80; Then you can achieve that by using a char[], which doesn't get encoded/decoded when creating a string.
If you use a byte[] (as you have done in your example), then it will get decoded and invalid characters get mapped to 0xFFFD, which is unicode replacement character.
It's because you converted � symbol to hex incorrectly (0x80). 1 symbol in UTF-8 can take 1 byte or more. In your case � symbol takes 2 bytes and have the following representation 65533 or 0xFFFD. So, if you replace your code with
int index = variable.lastIndexOf(0xFFFD);
//index will be 8
all will work fine.
Code snippet to proof my words:
String variable = "serialno�";
for (char c : variable.toCharArray())
System.out.print(((int)c)+ " ");
// 115 101 114 105 97 108 110 111 65533
UPDATE
You've made a mistake in hexStringToBin function. Replace it with
public static String hexStringToBin(String s) {
int len = s.length();
char[] data = new char[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (char) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return new String(data);
}
and all will work fine.
This is working for me :
int hex = 0x6F;
System.out.println("serialno€".lastIndexOf((char)hex));
Output :
7
I'm dealing with a packed binary data file that I am trying to decode, modify and recode. I need to be able to repack float values in the same way that they were unpacked. The float value in this sample code is -1865.0. What do I need to do in byte4float so that the four bytes returned are the same as I started, ie (C3 74 90 00 ).
public class HelloWorld {
public static void main(String[] args) {
byte[] bytes = {(byte) 0xC3,(byte) 0X74,(byte) 0X90,(byte) 0X00 };
byte newbytes[] = new byte[4];
float f;
f = float4byte (bytes[0], bytes[1], bytes[2], bytes[3]);
System.out.println("VAL Bytes : " + f);
// Now see if we can reverse it
// NOT Working
newbytes = byte4float(f);
System.out.println ("TO Bytes: "+String.format("%02X ", newbytes[0])+
String.format("%02X ", newbytes[1])+String.format("%02X ", newbytes[2])+String.format("%02X ", newbytes[3]));
}
/**
* Convert four bytes into a float value. Byte parameters
*
* #param a highest byte
* #param b higher byte
* #param c lower byte
* #param d lowest byte
*
* #return float value
*/
private static float float4byte(byte a, byte b, byte c, byte d)
{
int sgn, mant, exp;
System.out.println ("IN Byte : "+String.format("%02X ", a)+
String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d));
mant = ( b &0xFF) << 16 | (c & 0xFF ) << 8 | ( d & 0xFF);
if (mant == 0) return 0.0f;
sgn = -(((a & 128) >> 6) - 1);
exp = (a & 127) - 64;
return (float) (sgn * Math.pow(16.0, exp - 6) * mant);
}
/**
* Convert float value into a four bytes.
*
* #param f float value to convert
*
* #return byte[0] highest byte, byte[1] higher byte, byte[2] lower byte, byte[3] lowest byte
*/
private static byte[] byte4float(float f)
{
byte newbytes[] = new byte[4];
int bits = Float.floatToIntBits(f);
newbytes[0] = (byte)(bits & 0xff);
newbytes[1] = (byte)((bits >> 8) & 0xff);
newbytes[2] = (byte)((bits >> 16) & 0xff);
newbytes[3] = (byte)((bits >> 24) & 0xff);
return newbytes;
}
}
The fact that your mantisse is 24 bit and exponent is 7 bits indicates that you are dealing with IBM style single precision floating points. I had some trouble figuring out why float4byte does sgn * Math.pow(16.0, exp - 6) * mant, when I realized that simply is the same as sgn * Math.pow(16, exp) * (mant / Math.pow(2, 24), which is exactly the way IBM floats work.
What you are encoding are common IEEE-754 single precision floating points. The mis-match is causing the trouble.
On the IBM floating point architecture wikipedia article you can find an example of how to encode a floating point number to IBM float bytes.
Thanks to #halfbit input, and some minor changes, this routine will convert IEEE 754 float to IBM float.
public static byte[] byte4float(float f) {
assert !Float.isNaN(f);
// see also JavaDoc of Float.intBitsToFloat(int)
int bits = Float.floatToIntBits(f);
int s = (bits >> 31) == 0 ? 1 : -1;
int e = (bits >> 23) & 0xFF;
int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000;
int exp = (e - 150) / 4 + 6;
int mant;
int mantissaShift = (e - 150) % 4; // compensate for base 16
if (mantissaShift >= 0) mant = m >> mantissaShift;
else mant = m >> (Math.abs(mantissaShift));
if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision */
byte a = (byte) ((1 - s) << 6 | (exp + 64));
return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant };
}
I think this is right and appears to be working.
I am wondering how can I turn my 32 character int into a 32-byte array as it is represented.
Example:
I have this int:
int test = 123456789;
And I want to turn it into this:
byte[] Write_Page_Four = new byte[] {
(byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x01, (byte) 0x23, (byte) 0x45,
(byte) 0x67, (byte) 0x89};
Currently, I'm thinking of splitting my int by 2 and just manually assigning them to the byte array but I am having some troubles in doing so, and I believe that this is not the best practice for my problem.
This is what I have ATM, which is returning error and still work on progress though and I could use some advice on it:
String test2 = "01";
String test1 = "0x"+test2;
byte test = Byte.valueOf(test1);
System.out.println("teeeeest-----"+test);
byte[] Write_Page_Four = new byte[] {(byte) test};
And this one is returning an error:
java.lang.NumberFormatException: For input string: "0x01"
What is causing problems
Byte.valueOf doesn't parse data like the Java compiler does: it expects as input as a decimal number.
What you can use however, is Byte.valueOf(String,int) with an arbitrary radix. In that case you can solve it using:
byte test = Byte.valueOf(test2,16); //using test2, not test1
Mind that should not add "0x" in the front. Nevertheless this is an inefficient way to do this.
Ints are 32-bits, not 32-bytes
A second problem is that you state that you can store a number like 12345678901234567890123456789011 into an int. You cannot. An int has 32 bits. This means its representation is limited to more or less 2.1B. So I think you mean you store 12345678901234567890123456789011 in a String?
Number systems
Mind that the number 12345678901234567890123456789011 is not represented internally as (byte) 0x12, (byte) 0x34,... unless you are working with binary coded decimals. This is because a computer uses the binary number system (and thus groups bytes with the hexadecimal representation), whereas humans use the decimal representation. 123456789 for instance will be represented as 0x07,0x5B,0xCD 0x15.
Serializing an int (or other datastructure) using an array of bytes
You can convert an int (and other datatypes) into an array of bytes using this code:
ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(test);
byte[] result = b.array(); //result will be 4 bytes,
//since you can represent any int with four bytes.
Or, in case you want to represent the int like the way you do this, you could use the following method:
int t = test;
byte[] dat = new byte[5];//at most 5 bytes needed
for(int j = 4; test != 0; j--) {
int rm = t%100;
dat[j] = (byte) (rm%10+((rm/10)<<8));
t /= 100;
}
//result is dat
Instead of processing the textual representation of the number I'd recommend to simply calculate the single numbers:
Get two digits of the number each time:
int inp = 1234...;
for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE ; lowerBound *= 100)
//twoDigit contains two digits of the input-number
int twoDigit = (inp /lowerBound) % 100;
Transform these two digits into a byte:
byte transform(int i){
if(i == 0)
return 0x00;
int lsd = (i % 10); //least significant digit of the input (decimal)
int msd = (i / 10); //most significant digit
//merge lsd and msd into a single number, where the lower 4 bits are reserved for
//lsd and the higher 4 bits for msd
return lsd | (msd << 4);
}
The complete code would look like this:
import java.util.Arrays;
public class test
{
private static final int BYTES = 4;
public static void main(String[] args){
int v = 12345678;
int at_arr = BYTES - 1;
byte[] result = new byte[BYTES];//int is 32-bit/4 byte long
for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE && at_arr > -1; lowerBound *= 100, at_arr--)
result[at_arr] = transformDigits((v / lowerBound) % 100);
for(byte b : result)
System.out.print(" 0x" + Integer.toString(b , 16) + ",");
System.out.println();
}
static byte transformDigits(int i){
if(i == 0)
return 0x00;
int lsd = (i % 10); //least significant digit of the input (decimal)
int msd = (i / 10); //most significant digit
//merge lsd and msd into a single number, where the lower 4 bits are reserved for
//lsd and the higher 4 bits for msd
return (byte) (lsd | (msd << 4));
}
}
This code can be used basically for any integral type, if the types and value of BYTES are updated appropriately.
Here's how to convert an int to a byte[]:
int test = 123456789;
byte[] bytes = new byte[4];
bytes[0] = (byte)(test >> 24);
bytes[1] = (byte)(test >> 16);
bytes[2] = (byte)(test >> 8);
bytes[3] = (byte)test;
System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);
Output
07 5b cd 15
You can also inline it, if you want:
int test = 123456789;
byte[] bytes = new byte[] { (byte)(test >> 24),
(byte)(test >> 16),
(byte)(test >> 8),
(byte)test };
System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);
How to encode a 7 digit integer to a 4 digit string In java?
I have a base36 decoder, which is generating 6 characters,
ex:230150206 is converted to 3T0X1A.
The code for it is as follows:
String f = "230150206";
int d = Integer.parseInt(f.toString());
StringBuffer b36num = new StringBuffer();
do {
b36num.insert(0,(base36(d%36)));
d = d/ 36;
} while (d > 36);
b36num.insert(0,(base36(d)));
System.out.println(b36num.toString());
}
/**
Take a number between 0 and 35 and return the character reprsenting
the number. 0 is 0, 1 is 1, 10 is A, 11 is B... 35 is Z
#param int the number to change to base36
#return Character resprenting number in base36
*/
private static Character base36 (int x) {
if (x == 10)
x = 48;
else if (x < 10)
x = x + 48;
else
x = x + 54;
return new Character((char)x);
}
Can some one share me some other way to achieve this?.
The obtained string can be made in to a substring, but i am looking any other way to do it.
Here is a method, in a simple test program. This method allows any String to represent the digits for the result. As the initial print shows, 62 digits should be sufficient to cover all 7 decimal digit numbers with no more than a 4 character output, so I recommend the decimal digits, lower case alpha and upper case alpha for the 7 digit case.
To cover 9 decimal digits in four encoded digits you would need at least 178 characters, which is not possible using only the 7-bit ASCII characters. You would have to decide which additional characters to use as digits.
public class Test {
public static void main(String[] args) {
String characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
System.out.println(Math.pow(characters.length(), 4));
testit(230150206, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
testit(230150206, characters);
}
private static void testit(int num, String characters){
System.out.println(num + " "+compact(num, characters));
}
public static String compact(int num, String characters){
StringBuffer compacted = new StringBuffer();
while(num != 0){
compacted.insert(0, characters.charAt(num % characters.length()));
num /= characters.length();
}
return compacted.toString();
}
}
Output:
1.4776336E7
230150206 3T0X1A
230150206 fzGA6
All 7 digit numbers in base 10 can fit inside 24 bits (log2(9999999) < 24), that is 3 bytes. Ascii85 requires 20% of extra space to encode which will make it fit in 4 bytes.
Based on this answer by Mat Banik, you can do this:
public class Ascii85Test {
static int[] numbers = {
9999999,
490,
7910940,
};
public static void main(String[] args) {
for(int number : numbers) {
// Convert the number into 3 bytes
byte[] numberBytes = new byte[3];
numberBytes[0] = (byte) ((number >> 16) & 0xFF);
numberBytes[1] = (byte) ((number >> 8) & 0xFF);
numberBytes[2] = (byte) (number & 0xFF);
// Ascii85 encode the bytes
String encoded = Ascii85Coder.encodeBytesToAscii85(numberBytes);
// The encoded string will be "<4 characters>~\n", so we only need to keep the first 4 characters
encoded = Ascii85Coder.encodeBytesToAscii85(numberBytes).substring(0, 4);
// Decode them again, add the trailing ~ that we trimmed
byte[] decodedBytes = Ascii85Coder.decodeAscii85StringToBytes(encoded + "~");
// Convert the 3 bytes into a number
int decodedNumber = ((decodedBytes[0] << 16) & 0xFF0000)
| ((decodedBytes[1] << 8) & 0xFF00)
| (decodedBytes[2] & 0xFF);
System.out.printf("%s -> %s -> %s%n", number, encoded, decodedNumber);
}
}
}
Output:
9999999 -> R$N4 -> 9999999
490 -> !!2? -> 490
7910940 -> Gd\R -> 7910940
An int in Java can have a maximum of 10 digits (11 if you count the minus sign) and take up 4 bytes. With the 20% overhead of Ascii85 this means that we can encode any integer using 5 characters.
I need to convert a signed decimal number into a 32 bit little-endian binary value. Does anyone by any chance know of a built-in Java class or function that can do this? Or have built one to do this?
The data is a longtitude/latitude value like -78.3829. Thanks for any help.
If it helps at all, here's a class that I made that converts longs to binary Strings and binary Strings to longs:
public class toBinary {
public static void main(String[] args) {
System.out.println(decimalToBinary(16317));
System.out.println(binaryToDecimal("11111111111111111111111111111111111100101001"));
}
public static long binaryToDecimal(String bin) {
long result = 0;
int len = bin.length();
for(int i = 0; i < len; i++) {
result += Integer.parseInt(bin.charAt(i) + "") * Math.pow(2, len - i - 1);
}
return result;
}
public static String decimalToBinary(long num) {
String result = "";
while(true) {
result += num % 2;
if(num < 2)
break;
num = num / 2;
}
for(int i = result.length(); i < 32; i++)
result += "0";
result = reverse(result);
result = toLittleEndian(result);
return result;
}
public static String toLittleEndian(String str) {
String result = "";
result += str.substring(24);
result += str.substring(16, 24);
result += str.substring(8, 16);
result += str.substring(0, 8);
return result;
}
public static String reverse(String str) {
String result = "";
for(int i = str.length() - 1; i >= 0; i--)
result += str.charAt(i);
return result;
}
}
It doesn't take decimal values, but it could probably give you a bit of guidance.
The conversion is trivial once you know what the endianess means on binary level. The question is more what do you really want to do with it?
public static int flipEndianess(int i) {
return (i >>> 24) | // shift byte 3 to byte 0
((i >> 8) & 0xFF00) | // shift byte 2 to byte 1
(i << 24) | // shift byte 0 to byte 3
((i & 0xFF00) << 8); // shift byte 1 to byte 2
}
This little method will swap around the bytes in an int to switch between little/big endian order (the conversion is symetric). Now you have a little endian int. But what would you do with that in Java?
More likely you need to write the data to a stream or something, then its only a question in which order you write the bytes out:
// write int to stream so bytes are little endian in the stream
// OutputStream out = ...
out.write(i);
out.write(i >> 8);
out.write(i >> 16);
out.write(i >> 24);
(For big endian you would just order the lines from bottom to top...)