Is this the correct way to bit shift into a char?
char value = (char)((array[offset] << 9) + (array[offset + 1]));
If not, please correct me.
Bytes in Java are a bit tricky.
They don't go from 0 to 255 like you might be used to from other languages. Instead, they go from 0 to 127 and then from -128 to -1.
This means, that all bytes in your byte array that is below 128 will be converted into the correct char with this code:
char value = (char)((array[offset] << 8) + (array[offset + 1]));
But if the byte value is above 127, you'll probably get results you didn't expect.
Small example:
class test {
public static void main(String[] args) {
byte b = (byte)150;
char c = (char)b;
int i = (int)c;
System.out.println(b);
System.out.println(c);
System.out.println(i);
}
}
Will output this:
-106
ヨ
65430
Not exactly what you might expect. (Depending of course how well you know Java).
So to properly convert 2 bytes into a char, you'd probably want a function like this:
char toChar(byte b1, byte b2) {
char c1 = (char)b1;
char c2 = (char)b2;
if (c1<0) c1+=256;
if (c2<0) c2+=256;
return (char)((c1<<8)+c2);
}
Related
Given an array filled with 4 bytes inside (R,G,B,A), I'm trying to translate this array full of 4 8bits numbers into its translation in 32bits. To be more clear, if I get an array such as:
byte[] tab = {1,2,3,4};
with translated in binary in 8bit :
1 = 0b00000001
2 = 0b00000010
3 = 0b00000011
4 = 0b00000100
Then, my method should return a byte array such as :
newTab = {00000001_00000010_00000011_00000100};
For some reason, I'm trying to do this without using a String to concatenate the bytes.
I've already tried something with binary operators such as <<, >> or |, but without success...
So far, my code looks like this :
byte[] tab = {1,2,3,4};
int tmp,tabToInt = 0;
for (int x = 0 ; x < tab.length ; ++x){
tmp = tmp << (tab.length - 1 - x)*8;
byteToInt = byteToInt | tmp;
}
return tabToInt;
But it didn't seem to work, even less with negatives bytes... (like -1 = 0b11111111)
Thanks in advance for your answers!
You can use ByteBuffer like this.
byte[] tab = {1, 2, 3, 4};
int tabToInt = ByteBuffer.wrap(tab).getInt();
System.out.println("decimal = " + tabToInt);
System.out.println("binary = " + Integer.toBinaryString(tabToInt));
System.out.println("hexadecimal =" + Integer.toHexString(tabToInt));
output
decimal = 16909060
binary = 1000000100000001100000100
hexadecimal =1020304
ByteBuffer can do it, but only if you get passed at least 4 bytes.
The problem with your code is two-fold:
I think you typoed somewhere, your code doesn't even compile. I think you meant tmp = tab[x] << (tab.length - 1 - x)*8;. Your snippet never does anything with tab other than ask for its length.
Negative numbers extend, and java will convert any byte or short to an int the moment you do any math to it. So, 0b1111 1111, if you try to do e.g. << 8 on that, java first turns that -1 byte into a -1 int (so that's now 32 1 bits), and then dutifully left shifts it by 8, so now that's 24 1 bits, followed by 8 0 bits. You then bitwise OR that into your target, and thus now the target is mostly 1 bits. To convert a byte to an int without "sign extension", (b & 0xFF does it:
byte b = (byte) 0b1111_1111;
assert b == -1; // yup, it is
int c = b; // legal
assert c == -1; // yeah, still is. uhoh. That's...
int d = 0b11111111_11111111_11111111_11111111;
assert c == d; // yeah. We don't want that.
int e = (b & 0xFF);
assert e = 255;
int f = 0b0000000_0000000_0000000_11111111;
assert e == f; // yes!
I am trying to reform a string from ascii characters. I noticed when I break down ascii it matches the number with the ascii char, this changes when I tried to do (c+=c+0) on it as seen below, I tried to revert back to the original string but it doesn't seems to work. I was wondering does the ascii number change when you append it to a string?
StringBuilder b = new StringBuilder();
char c = "e".charAt(0);
System.out.println(c); //'e'
System.out.println(c+0); //101 -ascii
b.append(c+=c+0);
char d = b.charAt(0);
System.out.println(d-=d+0); //blank
When you use + to sum a char with and int, the result will be promoted
to int.
When you use compound assignment operators +=, the result will be converted to left
operand data type(in this case, char)
This is what happens with your code:
StringBuilder b = new StringBuilder();
char c = "e".charAt(0);
System.out.println(c); //'e'
System.out.println(c+0); //101 -ascii
b.append(c+=c+0); // result of c+c+0 is int 202, it is converted to char Ê
char d = b.charAt(0); // char d = Ê
System.out.println(d-=d+0); // result of d-(d+0) is int 0, it will be converted to null
It's not clear what you're trying to accomplish, but hopefully this example helps you figure out what's going on:
public static void main(String[] args) {
StringBuilder b = new StringBuilder();
char c = "e".charAt(0);
System.out.println(c); // e
System.out.println((int) c); // 101
char doubleC = (char) (c + c);
b.append(doubleC);
char d = b.charAt(0);
System.out.println((int) d); // 202
System.out.println(d - c); // 101
System.out.println((char) (d - c)); // e
}
Whether a character is printed as a letter or its ASCII value depends on its type. You can see that (int) c casts the character to its int ASCII value. Your approach of c+0 also does this but in a less intuitive way.
You also apparently want to "undo" your modification to c, but subtracting d-d always gives you 0. You need to store your value of c and subtract that from d.
+0s don't do anything because the character is underneath a number (so it's essentially like saying 101 + 0).
d-=d+0 evaluates to d = d - d + 0, so (because we're manipulating chars) d - d = 0
If you wanted to get c from d, you'd have to do d = d - c, because 'c' is the difference between the initial and the final value.
So no, the ASCII number of a character doesn't change, you're just not doing the reverse calculation as you should be.
It's like saying: x + y = z,
and then wondering why z - z != y.
You should be doing: z - x = y
#Edit
To add to your comment under pkpnd's answer - if you have only String b to work with, you'd still need to know the difference (i.e. by how much you increased/decreased the number) to reverse to the original chars.
I have following java program:
public class java {
public static void main(String[] args) {
byte a=64, b;
int i;
i=a<<2;
b=(byte)(a<<2);
System.out.println(i);
System.out.println(b);
}
}
In this program, how the value of b is zero? I didn't get it.
Because a byte is exactly 8 bits. And the last 8 bits of your int are 0. If we add the result of Integer.toBinaryString(int) like,
byte a = 64;
int i = a << 2;
System.out.println(Integer.toBinaryString(i));
byte b = (byte) (a << 2);
you'll see that the output is
100000000
so b (because the 1 is the ninth bit) becomes
00000000
(which is 0).
I'm trying to create a new byte knowing a certain amount of bits
char prostie1 = theRepChars[j-3];
char prostie2 = theRepChars[j-2];
char prostie3 = theRepChars[j-1];
char prostie4 = theRepChars[j];
String prostiaMare = prostie4 + prostie3 + prostie2 + prostie1 + "";
Byte theChar = new Byte(prostiaMare);
When i do this I get a NumberFormatException value 196.
I have no idea what might be my problem
--EDIT--
Ok I think I might have to give some more details since I wasn't very clear. I'm trying to do an Uuencode algorithm and by following the logic of the algorithm I should stop my byte having a value bigger than 194. Here is a bunch of my code.
if(my_chars.length % 3 == 0)
{
for(int x = 0; x < my_chars.length; x++)
{
if((x+1) % 3 == 0)
{
char first = my_chars[x-2];
char second = my_chars[x-1];
char third = my_chars[x];
int n = (((first << 8) | second) << 8) | third;
String theRep = Integer.toBinaryString(n);
while(theRep.length() < 24 - 1)
{
theRep = 0 + theRep;
}
//0 padded theRep
for(int j = 0; j < theRepChars.length; j++)
{
if((j+1) % 4 == 0)
{
char prostie1 = theRepChars[j-3];
char prostie2 = theRepChars[j-2];
char prostie3 = theRepChars[j-1];
char prostie4 = theRepChars[j];
String prostiaMare = prostie4 + prostie3 + prostie2 + prostie1 + "";
System.out.println(prostiaMare);
}
}
}
}
}
And trying to create a new byte with the value that prostiaMare has gives me the numberFormatException. I'm not sure if I have not followed the algorithm right ( http://www.herongyang.com/encoding/UUEncode-Algorithm.html )
196 is outside the range of byte, a signed value. Bytes can range from -128 to 127.
I'm not sure why you're casting to String. If you just want a byte with bits equivalent those of the sum of the four chars, cast directly to byte:
(byte) (prostie4 + prostie3 + prostie2 + prostie1)
If you intended to construct a String from the four chars, you are not currently doing that. Use:
"" + prostie4 + prostie3 + prostie2 + prostie1
and, if the result is in the range of a byte, you can create a byte as you have been.
Bytes are signed in Java. Which means a byte, which is 8 bits long, has a minimum value of -2^7 (-128) and a max value of 2^7 - 1 (127). Java has no unsigned primitive types apart from char (unsigned, 16bit).
Therefore 196 is unparseable --> NumberFormatException.
You don't have much to work around this except to read into a larger type and do & 0xff to obtain the byte:
final int i = Integer.parseInt(theString);
final byte b = (byte) (i & 0xff);
Or do yourself a favour and use Guava, which has UnsignedBytes:
final byte b = UnsignedBytes.parseUnsignedByte(theString);
But it appears that you want to do comparisons anyway; so just use a larger type than byte. And no, this won't waste memory: don't forget about alignment.
As mentioned in the docs
An exception of type NumberFormatException is thrown if any of the following situations occurs:
The first argument is null or is a string of length zero.
The radix is either smaller than Character.MIN_RADIX or larger than Character.MAX_RADIX.
Any character of the string is not a digit of the specified radix, except that the first - character may be a minus sign '-' ('\u002D') provided that the string is longer than length 1.
The value represented by the string is not a value of type byte.
In your case its the last case since 196 cant be represented as byte..The valid range is -128 to 127
How can I convert couple of characters to int, to keep the question simple let's assume this :
char c1 = '1';
char c2 = '4';
char c3 = '5';
What would be the efficient way to get 145 type int.
int myInt = Integer.parseInt(""+c1+c2+c3);
""+c1 gives you a String containing the char c1, to which you append the characters c2 and c3. Then you use parseInt() to convert it to an integer.
A more straightforward (but less robust) method would be this:
int myInt = 100*(c1-'0') + 10*(c2-'0') + (c3-'0');
c1-'0' gives you the number represented by c1 as opposed to the character code. Then you simply shift things to the correct decimal places and add.
int myInt = (c1 - '0') * 100 + (c2 - '0') * 10 + (c3 - '0');
Here is a more general method to convert a char array to int:
int valueOf(char[] input){
int result = 0;
for(char c : input) {
result *= 10;
result += Character.digit(c, 10);
}
return result;
}
The most correct way to convert a single digit character to an int is Character.digit(char ch, int radix), which can handle values in bases besides 10.
Strings are ultimately backed by a char[], so you could do the following:
char c1 = '1';
char c2 = '4';
char c3 = '5';
int converted = Integer.parseInt(new String(new char[]{c1, c2, c3}));
There are probably several other perfectly good ways to do this.