Translating an array of chars into an array of numbers in Java - java

So, what I need to do is translate an array of chars into an array of numbers.
I know this sounds like an odd request, but here's what I've been trying to do:
Have an array like this:
charArray[0] = e;
charArray[1] = b;
charArray[2] = p;
and have it translatated into:
numArray[0] = 5;
numArray[1] = 2;
numArray[2] = 16;
So it would translate the char into it's position in the alphabet (eg. "a" is the 1st letter, "b" is the 2nd, etc)
What's the best way of doing this? I was going to attempt to do it one by one, but then realized I would have way too many lines of code, it would just be tons of nested if statements, and I figured there's probably some better way to do it.
(My way was going to be if charArray[0] = a then numArray[0] = 1, and go through every single letter like that, until you get to if charArray[0] = z then numArray[0] = 26, but that would require 26 different if statements PER CHAR in the char array, which would be a horrible way of doing it in my opinion, because my char array is extremely long.)

You can use a trick For each index i:
numArray[i] = charArray[i] - 'a' + 1;
A more "by the book" way of doing it is:
final String letters = "abcdefghijklmnopqrstuvwxyz";
. . .
numArray[i] = letters.indexOf(charArray[i]) + 1;
Then any positions i such that charAray[i] is not a lower-case letter will end up as 0 in numArray[i]. With the trick, the value of numArray[i] will be something unpredictable.

You can simply:
numArray[i] = charArray[i] - 'a' + 1;
Explanation:
Looking at the ascci table you'll see the decimal value of each char.
a has the decimal value of 97. So you remove 97 from it and add 1. You get 1.
The same for b...z, removing 97 (a) from 98 (b) will be 1, and you add 1 to get 2.. and so on..

Assume all characters are lowercase, you can write:
numArray[0] = (charArray[0] - 'a' + 1);
If you have lowercase and uppercase, you can use an if statement like:
if (charArray[0] >= 'A' && charArray[0] <= 'Z') {
numArray[0] = (charArray[0] - 'A' + 1);
} else {
numArray[0] = (charArray[0] - 'a' + 1);
}

Related

Get the Unicode from a Hexadecimal

I've been searching for a solution to my problem for days but can't get a spot-on answer when looking at previously answered questions/ blogs / tutorials etc. all over the internet.
My aim is to write a program which takes a decimal number as an input and then calculates the hexadecimal number and also prints the unicode-symbol of said hexadecimal number (\uXXXX).
My problem is I can't "convert" the hexadecimal number to unicode. (It has to be written in this format: \uXXXX)
Example:
Input:
122 (= Decimal)
Output:
Hexadecimal: 7A
Unicode: \u007A | Unicode Symbol: Latin small letter "z"
The only thing I've managed to do is print the unicode (\u007A), but I want the symbol ("z").
I thought if the unicode only has 4 numbers/letters, I would just need to "copy" the hexadecimal into the code and fill up the remaining places with 0's and it kinda worked, but as I said I need the symbol not the code. So I tried and tried, but I just couldn't get the symbol.
By my understanding, if you want the symbol you need to print it as a string.
But when trying it with a string I get the error "illegal unicode escape".
It's like you only can print pre-determined unicodes and not "random" ones generated on the spot in relation of your input.
I'm only a couple days into Java, so apologies if I have missed anything.
Thank you for reading.
My code:
int dec;
int quotient;
int rest;
int[]hex = new int[10];
char[]chars = new char[]{
'F',
'E',
'D',
'C',
'B',
'A'
};
String unicode;
// Input Number
System.out.println("Input decimal number:");
Scanner input = new Scanner(System.in);
dec = input.nextInt();
//
// "Converting to hexadecimal
quotient = dec / 16;
rest = dec % 16;
hex[0] = rest;
int j = 1;
while (quotient != 0) {
rest = quotient % 16;
quotient = quotient / 16;
hex[j] = rest;
j++;
}
//
/*if (j == 1) {
unicode = '\u000';
}
if (j == 2) {
unicode = '\u00';
}
if (j == 3) {
unicode = '\u0';
}*/
System.out.println("Your number: " + dec);
System.out.print("The corresponding Hexadecimal number: ");
for (int i = j - 1; i >= 0; i--) {
if (hex[i] > 9) {
if (j == 1) {
unicode = "\u000" + String.valueOf(chars[16 - hex[i] - 1]);
}
if (j == 2) {
unicode = "\u00" + String.valueOf(chars[16 - hex[i] - 1]);
}
if (j == 3) {
unicode = "\u0" + String.valueOf(chars[16 - hex[i] - 1]);
}
System.out.print(chars[16 - hex[i] - 1]);
} else {
if (j == 1) {
unicode = "\u000" + Character.valueOf[hex[i]);
}
if (j == 2) {
unicode = "\u00" + Character.valueOf(hex[i]);
}
if (j == 3) {
unicode = "\u0" + Character.valueOf(hex[i]);
}
System.out.print(hex[i]);
}
}
System.out.println();
System.out.print("Unicode: " + (unicode));
}
It's not an advanced code whatsoever, I wrote it exactly how I would calculate it on paper.
Dividing the number through 16 until I get a 0 and what remains while doing so is the hexadecimal equivalent.
So I put it in a while loop, since I would divide the number n-times until I got 0, the condition would be to repeat the division until the quotient equals zero.
While doing so the remains of each division would be the numbers/letters of my hexadecimal number, so I need them to be saved. I choose an integer array to do so. Rest (remains) = hex[j].
I also threw a variable in the called "j", so I would now how many times the division was repeated. So I could determine how long the hexadecimal is.
In the example it would 2 letters/numbers long (7A), so j = 2.
The variable would then be used to determine how many 0's I would need to fill up the unicode with.
If I have only 2 letters/numbers, it means there are 2 empty spots after \u, so we add two zeros, to get \u007A instead of \u7A.
Also the next if-command replaces any numbers higher than 9 with a character from the char array above. Basically just like you would do on paper.
I'm very sorry for this insanely long question.
U+007A is the 3 bytes int code pointer.
\u007A is the UTF-16 char.
A Unicode code pointer, symbol, sometimes is converted to two chars and then the hexadecimal numbers do not agree. Using code pointers hence is best. As UTF-16 is just an encoding scheme for two-bytes representation, where the surrogate pairs for 3 byte Unicode numbers do not contain / or such (high bit always 1).
int hex = 0x7A;
hex = Integer.parseUnsignedInt("007A", 16);
char ch = (char) hex;
String stringWith1CodePoint = new String(new int[] { hex }, 0, 1);
int[] codePoints = stringWith1CodePoint.codePoints().toArray();
String s = "đť„ž"; // U+1D11E = "\uD834\uDD1E"
You can simply use System.out.printf or String.format to do what you want.
Example:
int decimal = 122;
System.out.printf("Hexadecimal: %X\n", decimal);
System.out.printf("Unicode: u%04X\n", decimal);
System.out.printf("Latin small letter: %c\n", (char)decimal);
Output:
Hexadecimal: 7A
Unicode: u007A
Latin small letter: z

Negative string index

I am doing some kind of cipher in Java for schools homework. The task is to change the value of a certian char to a new one with a specific offset which is given by the user and has a range from negative numbers to positive numbers (alphabet).
Now I have a problem with negative offsets. I have created a String with the Alphabet which helps to find the new char. For example: With the offset of 7 I got this: encrypt(“TEST”) = “ALZA”. So my code grabs the index of the string value and searches with this index in the alphabet string for the new char. Anyway when I now have the char 'E' and a negative index i.e '-7' it will return the value of -3 for the new index of the new char (I hope that makes sense). Since there is no char on index '-3' I get an error.
So how can I access to the end of the string instead of going more and more into negative index numbers ?
Add 26 then mod 26:
i = (i + 26) % 26;
This always works for indexes down to -26. If that's not enough, just add some zeroes:
i = (i + 26000000) % 26;
Your general problem appears to be that letters are represented by only 26 indices, but the actual index variable you use might be greater than 26, or even less than zero (negative). One way to handle this problem is to use the mod operator to safely wrap your index around to always point to a range containing a valid letter.
Here is logic which can do that:
if (index < 0) {
index = (index % 26) + 26;
}
else {
index = index % 26;
}
Assuming the letter E is position 5 and you have a reassignment of -7, this would mean that the new index would be -2. This new position can be mapped using the above logic as follows, where index = -2 in this case:
5 - 7 = -2
(-2 % 26) + 26
-2 + 26
24
And character in position 24 is the letter X.
If you can constrain shift values to be positive, you can use remainder operator:
int newIndex = (index + shift) % 26
If there are negatives to be expected:
int newIndex = Math.floorMod(inndex + shift, 26) would do the trick
Actually you need mathematical modulo, but % operator is not quite that

How do I get the numerical value/position of a character in the alphabet (1-26) in constant time (O(1)) without using any built in method or function?

How do I get the numerical value/position of a character in the alphabet (1-26) in constant time (O(1)) without using any built in method or function and without caring about the case of the character?
If your compiler supports binary literals you can use
int value = 0b00011111 & character;
If it does not, you can use 31 instead of 0b00011111 since they are equivalent.
int value = 31 & character;
or if you want to use hex
int value = 0x1F & character;
or in octal
int value = 037 & character;
You can use any way to represent the value 31.
This works because in ASCII, undercase values are prefixed with 011, and uppercase 010 and then the binary equivalent of 1-26.
By using the bitmask of 00011111 and the AND operand, we covert the 3 most significant bits to zeros. This leaves us with 00001 to 11010, 1 to 26.
Adding to the very good (self) answer of Charles Staal.
Assuming ascii encoding following will work. Updated from the kind comment of Yves Daoust
int Get1BasedIndex(char ch) {
return ( ch | ('a' ^ 'A') ) - 'a' + 1;
}
This will make the character uppercase and change the index.
However a more readable solution (O(1)) is:
int Get1BasedIndex(char ch) {
return ('a' <= ch && ch <= 'z') ? ch - 'a' + 1 : ch - 'A' + 1;
}
One more solution that is constant time but requires some extra memory is:
static int cha[256];
static void init() {
int code = -1;
fill_n (&cha[0], &cha[256], code);
code = 1;
for(char s = 'a', l = 'A'; s <= 'z'; ++s, ++l) {
cha[s] = cha[l] = code++;
}
}
int Get1BasedIndex(char ch) {
return cha[ch];
}
We can get their ASCII values and then subtract from the starting character ASCII(a - 97, A - 65)
char ch = 'a';
if(ch >=65 && ch <= 90)//if capital letter
System.out.println((int)ch - 65);
else if(ch >=97 && ch <= 122)//if small letters
System.out.println((int)ch - 97);
Strictly speaking it is not possible to do it portably in C/C++ because there is no guarantee on the ordering of the characters.
This said, with a contiguous sequence, Char - 'a' and Char - 'A' obviously give you the position of a lowercase or uppercase letter, and you could write
Ord= 'a' <= Char && Char <= 'z' ? Char - 'a' :
('A' <= Char && Char <= 'Z' ? Char - 'A' : -1);
If you want to favor efficiency over safety, exploit the binary representation of ASCII codes and use the branchless
#define ToUpper(Char) (Char | 0x20)
Ord= ToUpper(Char) - 'a';
(the output for non-letter character is considered unspecified).
Contrary to the specs, these snippets return the position in range [0, 25], more natural with zero-based indexing languages.

Specific digit detector issue

I have written a small piece of code where you enter a 3 digit number via the command line, and then it detects how many 5's are in the code.
public class fivedet {
public static void main (String[] args) {
String input = args[0];
int[] a = {0,0,0};
int x = 0;
int y = 0;
int z = 0;
for(int i = 0; i<input.length();i++) {
a[i] = input.charAt(i) - 48;
}
if(a[0]==5) {
x=5;
}
if(a[1]==5) {
y=5;
}
if(a[2]==5) {
z=5;
}
System.out.println("5 digits here:" + x + y + z);
}
}
My main question is why I require the -48 term after the input.charAt(i) method in order for each value in a[] to be equal to the actual number I input.
For example I enter
java fivedet 505
and without the -48 the array a[]={53,48,53} instead of a[]={5,0,5} and I unfortunately am not experienced enough with coding java (began learning 3 months ago) to understand why this is happening.
I also do want to develop it to be able to detect different digits and for different lengths of input numbers.
I would appreciate any insight as to why this happens.
Subtracting 48 is a quick but slightly confusing way of converting from a character to an integer. It so happens that the character code for each digit is 48 away from its numeric value.
See this table of ASCII values. (Java uses unicode, not ascii - strings are UTF-16 internally - but the values are valid in this specific case). So the character '0' has the value 48; the character '9' has the value 57.
Another way of doing this would be to take 1-character substrings of input, then call Integer.parseInt() on that string, converting "1" to 1, "2" to 2, etc.
You don’t need to convert to int in order to detect character 5. Just count them as chars.
for (char i : args[0].toCharArray()) {
System.out.print(i == '5' ? i : '0');
}
Also this question has good answers to count occurrences of a char in string

Conversion from ASCII values to Char

String source = "WEDGEZ"
char letter = source.charAt(i);
shift=5;
for (int i=0;i<source.length();i++){
if (source.charAt(i) >=65 && source.charAt(i) <=90 )
letterMix =(char)(('D' + (letter - 'D' + shift) % 26));
}
Ok what I'm trying to do is take the string WEDGEZ, and shift each letter by 5, so W becomes B and E becomes J, etc. However I feel like there is some inconsistency with the numbers I'm using.
For the if statement, I'm using ASCII values, and for the
letterMix= statement, I'm using the numbers from 1-26 (I think). Well actually, the question is about that too:
What does
(char)(('D' + (letter - 'D' + shift) % 26)); return anyway? It returns a char right, but converted from an int. I found that statement online somewhere I didn't compose it entirely myself so what exactly does that statement return.
The general problem with this code is that for W it returns '/' and for Z it returns _, which I'm guessing means it's using the ASCII values. I really dont know how to approach this.
Edit: New code
for (int i=0;i<source.length();i++)
{
char letter = source.charAt(i);
letterMix=source.charAt(i);
if (source.charAt(i) >=65 && source.charAt(i) <=90 ){
letterMix=(char)('A' + ( ( (letter - 'A') + input ) % 26));
}
}
Well I'm not sure if this homework, so i'll be stingy with the Code.
You're Writing a Caesar Cipher with a shift of 5.
To address your Z -> _ problem...I'm Assuming you want all the letters to be changed into encoded letters (and not weird Symbols). The problem is ASCII values of A-Z lie between 65 and 90.
When coding Z (for eg), you end up adding 5 to it, which gives u the value 95 (_).
What you need to do is Wrap around the available alphabets. First isolate, the relative position of the character in the alphabets (ie A = 0, B = 1 ...) You Need to subtract 65 (which is ASCII of A. Add your Shift and then apply modulus 26. This will cause your value to wrap around.
eg, it your encoding Z, (ASCII=90), so relative position is 25 (= 90 - 65).
now, 25 + 5 = 30, but you need the value to be within 26. so you take modulus 26
so 30 % 26 is 4 which is E.
So here it is
char letter = message(i);
int relativePosition = letter - 'A'; // 0-25
int encode = (relativePosition + shift) % 26
char encodedChar = encode + 'A' // convert it back to ASCII.
So in one line,
char encodedChar = 'A' + ( ( (letter - 'A') + shift ) % 26)
Note, This will work only for upper case, if your planning to use lower case, you'll need some extra processing.
You can use Character.isUpperCase() to check for upper case.
You can try this code for convert ASCII values to Char
class Ascii {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
char ch=sc.next().charAt(0);
if(ch==' ') {
int in=ch;
System.out.println(in);
}
}
}

Categories

Resources