Getting a character to be represented by an int 0-25 - java

I'm working on a cryptography program that implements various traditional methods. For some of them it is best for my message to be represented as numbers 0-25. A is 0, B is 1, etc. This shift cipher is a case of that since you must take mod 26 for a wrap around. Also spaces and punctuation must be preserved.
Here is the code for the method that does the shift cipher:
public static void shift(char k, char eord)
{
if(eord=='E' || eord=='e')
{
int [] mi= new int[mc.length];
for(int i=0; i<mc.length; i++)
{
if ((mc[i]>='a' && mc[i]<='z') || (mc[i]>='A' && mc[i]<='Z'))
{
mi[i]=(int)(mc[i]+k);
mi[i]=mi[i]%26;
//mc[i]=(char)mi[i];
//System.out.println(mi[i]);
}
}
}
}
mc is an array of characters that holds the message and eord is a char that will determine whether to run the algorithm to encrypt or decrypt. What I have the code do is check to make sure that mc[i] is a letter and then add the char k (the key) and then I type cast it into an integer so I can mod 26. Something does not work correctly because when I have a key of 'b' (1) and see what the integer representation is it is definitely not correct. I also need to convert it back to a character when I'm done so I can give the user the plaintext/cipher text of the message.

To get an integer value of 0..25 of a character you need to make sure that you only get upper- or lowercase characters in the alphabet.
Let's assume lowercase. Then you can simply convert the characters to integer by subtracting the value of the 'a' character. As the character values are ordered as in the normal alphabet, this will give 'a' value of 0 and 'z' value of 25... and all the letters in between will get the correct value as well.
I'll show a lowercase version as I don't like shouting:
public class CharacterToZeroBasedIntegerRange {
public static int characterToIntegerRange(char c) {
if (c < 'a' || c > 'z') {
throw new IllegalArgumentException(String.format("Character with value %04X is not a letter", (int) c));
}
return c - 'a';
}
public static void main(String[] args) {
String test = "Hello world!".toLowerCase().replaceAll("[^a-z]", "");
System.out.println(test);
for (int i = 0; i < test.length(); i++) {
char c = test.charAt(i);
System.out.println(characterToIntegerRange(c));
}
}
}

Related

What makes the 'getCharNumber' method case-insensitive while it only every checks for lowercase (by author of CtCI)

public class Common {
public static int getCharNumber(Character c) {
int a = Character.getNumericValue('a');
int z = Character.getNumericValue('z');
int val = Character.getNumericValue(c);
if (a <= val && val <= z) {
return val - a;
}
return -1;
}
public static int[] buildCharFrequencyTable(String phrase) {
int[] table = new int[Character.getNumericValue('z') - Character.getNumericValue('a') + 1];
for (char c : phrase.toCharArray()) {
int x = getCharNumber(c);
if (x != -1) {
table[x]++;
}
}
return table;
}
}
Above algorithm was used for testing whether a string is a permuation of a palindrome and was authored by CtCI (Cracking the Coding Interview).
My question: Why is the getCharNumber method case-insensitive?
I thought it should to be case-sensitive as it only checks for lowercase characters.
Why is the getCharNumber case-insensitive?
The getCharNumber method uses Java's Character#getNumericValue(char) method for which its JavaDoc states in particular:
The letters A-Z in their uppercase ('\u0041' through '\u005A'), lowercase ('\u0061' through '\u007A'), and full width variant ('\uFF21' through '\uFF3A' and '\uFF41' through '\uFF5A') forms have numeric values from 10 through 35. This is independent of the Unicode specification, which does not assign numeric values to these char values.
Meaning that for example for character A and a this API method returns the same value, i.e. 10, and thus there's no case-sensitivity.
For reference, see also
Character.getNumericValue(..) in Java returns same number for upper and lower case characters
What is the reverse of Character.getNumericValue
Java Character literals value with getNumericValue()
Character.getNumericValue() issue
Character.getNumericvalue in char Frequency table

Too many characters in character literal error

I'm creating a stylish text app but on some places I'm getting an error ("Too many characters in character literal"). I am writing only one letter but when I paste it converts into many letters like this: "\uD83C\uDD89" and the original letter is "🆉".
Please tell me how to write this in a correct way.
for (int charOne = 0; charOne <= strBld.length() - 1; charOne++) {
char a = strBld.charAt(charOne);
char newCh = getSpecialCharEighth(a);
strBld.setCharAt(charOne, newCh);
}
private char getSpecialCharEighth(char a) {
char ch = a;
if (ch == 'Z' || ch == 'z') {
ch = '\uD83C\uDD89';
}
return ch;
}
A Java char stores a 16-bit value, i.e. can store 65536 different values. There are currently 137929 characters in Unicode (12.1).
To handle this, Java strings are stored in UTF-16, which is a 16-bit encoding. Most Unicode characters, known as code points, are stored in a single 16-bit value. Some are stored in a pair of 16-bit values, known as surrogate pairs.
This means that a Unicode character may be stored as 2 char "characters" in Java, which means that if you want your code to have full Unicode character support, you can't store a Unicode character in a single char value.
They can be stored in an int variable, where the value is then referred to as a code point in Java. It is however often easier to store them as a String.
In your case, you seem to be replacing Unicode characters, so a regex replacement call might be better, e.g.
s = s.replaceAll("[Zz]", "\uD83C\uDD89");
// Or like this if source file is UTF-8
s = s.replaceAll("[Zz]", "🆉");
UPDATE
If you want to keep a method for determining the replacement value, you could do this:
s = Pattern.compile(".").matcher(s).replaceAll​(mr -> getSpecialCharEighth(mr.group()));
private static String getSpecialCharEighth(String s) {
int cp = s.codePointAt(0);
if (cp >= 'A' && cp <= 'Z')
return Character.toString​(cp - 'A' + 0x1f170); // "🅰" - "🆉"
if (cp >= 'a' && cp <= 'z')
return Character.toString​(cp - 'a' + 0x1f170); // "🅰" - "🆉"
return s;
}
Note: replaceAll​(replacer) is Java 9+ and Character.toString(codePoint) is Java 11+.
UPDATE 2
Since question is tagged android, Java 9 and Java 11 APIs are not available, so here is Java 7+ solution.
StringBuffer buf = new StringBuffer(s.length() + 16);
Matcher m = Pattern.compile(".").matcher(s);
while (m.find())
m.appendReplacement(buf, getSpecialCharEighth(m.group()));
s = m.appendTail(buf).toString();
private static String getSpecialCharEighth(String s) {
int cp = s.codePointAt(0);
if (cp >= 'A' && cp <= 'Z')
return new String(new int[] { cp - 'A' + 0x1f170 }, 0, 1);
if (cp >= 'a' && cp <= 'z')
return new String(new int[] { cp - 'a' + 0x1f170 }, 0, 1);
return s;
}
Result with s = "Hello World!"
🅷🅴🅻🅻🅾 🆆🅾🆁🅻🅳!
You can't do that with char data type. Use String instead.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).

Trouble with finding odd and even index values for characters

I'm creating simple encryption/decryption software as a fun project. I am able to encrypt. It gives me the encrypted password and the key. The problem I'm having is in the decryption. For an example, here is an encrypted message: eUwG:Q_vul=u^CMiojpnif and here is the key: 103141109141719141119050117050318040907010912. The way it works is by first adding a random salt to the beginning or end of the message which is defined by the first number in the key. So since the first number is 1 then the salt is at the beginning (the salts are 14 characters long), so it removes that text, leaving Miojpnif. In the key after the salt number, there are 2 numbers per letter in the text. which is where I'm stuck. A number 1 means that the character was shifted forward, and 0 means backwards. So for the 'M' in the key for that character it's 0 so it was shifted backwards and the next number is 3 meaning that it was shifted backwards by 3. So to reverse this I need to shift that character forward 3. The thing is, I can't figure out how to make this work properly. My idea is that it removes the first number (salt) from the key, and then if the number is odd, then it records if the character will go forward or back, and if it's even then it'll move that character forward or back (which is stored as an int like the rest) by that number. So where I'm stuck is that figuring out if it's even or odd isn't working properly and I can't quite figure out how to shift that character.
I already looked up how to figure out if it's even or odd, but it still doesn't work. Actually shifting the character I made up my own code for. I don't know if you guys understand what I need help with because I didn't really know how to express it in words. So here is the code that I have, I hope that y'all can help.
for(int i= 0; i < keyNew.length(); i++){
if(i % 2 == 1){
/*odd*/
if(keyNew.charAt(i) == '1') {
forward = 1;
backward = 0;
} else {
forward = 0;
backward = 1;
}
}else{
/*even*/
if(forward == 1 && backward == 0) {
/*forward*/
System.out.println("forward");
String encryptedNewer = encryptedNew.charAt(i / 2) += keyNew.charAt(i);
} else if(forward == 0 && backward == 1) {
*backward*/
System.out.println("backward");
String encryptedNewer = encryptedNew.charAt(i / 2) += keyNew.charAt(i);
}
}
}
encrypted is the encrypted text, key is the key, encryptedNew is the text without the salt and keyNew is the key without the first digit.
This is a great example of the long method smell. I recommend the following:
Work with String and use the substring(...) function. It is easier, because you need less variables and don't have to convert from char to int and back.
Create a function encrypt(...) and decrypt(...) which calls some "subfunctions"
One subfunction is addSalt(...) and removeSalt(...)
One subfunction is splitKeyToPairs(...) which returns a List of strings with 2 Digits per Item.
One subfunction is shiftForward(...) and shiftBackwards(...)
Then I would implement it as follow:
public String decrypt(String key, String cipher) {
String cipherModified = removeSalt(key, cipher);
List<String> keyPairs = splitKeyToPairs(key.substring(1, key.length()));
String message = "";
for(int position = 0; position < keyPairs.size();++position) {
String keyTmp = keyPairs.get(position);
String cipherLetter = cipherModified.substring(position, position + 1);
message += "0".equals(keyTmp.substring(0, 1)) ? shiftBackwards(cipherLetter, keyTmp.substring(1, 2)) : shiftForward(cipherLetter, keyTmp.substring(1, 2));
}
return message;
}
public List<String> splitKeyToPairs(String key) {
List<String> result = new ArrayList<String>();
for(int i = 0; i < key.length(); i += 2) {
//i += 2 because we jump 2 characters per iteration.
result.add(key.substring(i, i+2));
}
return result;
}
Here a little test function for the split but not for the decrypt:
public static void main(String[] args) {
List<String> result = splitKeyToPairs("1234567890");
List<String> test = new ArrayList<>(Arrays.asList("12", "34", "56", "78", "90"));
for(int i = 0; i < result.size();++i) {
if(!result.get(i).equals(test.get(i))) {
System.out.println("error on position " + i);
}
}
}
Ok, here is another approach to decrypting the message. Establishing methods and tucking them away in a library would be advisable. In the following example I omitted the salt digit from the key. The logic to accommodate that is trivial.
String key = "03141109141719141119050117050318040907010912";
String code = "eUwG:Q_vul=u^CMiojpnif";
int i = 0;
StringBuilder sb = new StringBuilder();
for (int pos = 0; pos < code.length(); pos++) {
// get codeLetter
char codeLetter = code.charAt(pos);
// set direction
int direction = key.charAt(i++) == '0' ? 1
: -1;
// set count
int count = key.charAt(i++) - '0';
// modify codeLetter based on direction and count
char c = (char) (codeLetter + (count * direction));
// save it.
sb.append(c);
}
System.out.println(sb.toString().substring(14));

Print 10 characters per line

hello i have some trouble doing my coding on this question;
Write a method that prints characters using the following header:
public static void printChars(char ch1, char ch2, int numberPerLine)
This method prints the characters between ch1 and ch2 with the specified numbers per line. Write test program that prints ten characters per line from ‘l’ and ‘Z’.
can somebody show me the coding sample to solve my problem? thanks
Here is some code that seems to wok on my end.
public static String alphabet = "abcdefghijklmnopqrstuvwxyz";
public static void printChars(char ch1, char ch2, int numberPerLine){
int currentNumber = numberPerLine;
int beginningIndex = alphabet.indexOf((ch1 + "").toLowerCase()) + 1;
int endingIndex = alphabet.indexOf((ch2 + "").toLowerCase());
for(int i = beginningIndex; i < endingIndex; i++){
System.out.print(alphabet.charAt(i));
if(currentNumber > 1){
currentNumber --;
}else{
System.out.println("");
currentNumber = numberPerLine;
}
}
}
public static void main(String[] args) {
printChars('c', 'z', 2);
}
Characters are encoded in ASCII. Each character has a unique decimal number representation. We can access these characters by their numbers, rather than the actual character.
For example, the character 'A' has an ASCII code of 65. We don't really need to know the integer codes to use their respective character representations though. We can just typecast the integers into chars.
We can also use characters in simple arithmetic. Since 'A' has ASCII code 65, then it makes sense for 65 + 1 = 66 to represent the character 'B'. Indeed it does.
public static void printChars(char ch1, char ch2, int numberPerLine) {
if(ch1 <= 'Z' && ch2 >= 'a')
return;
int count = 0; //count number of characters on a line.
char nextChar = ch1; //initialize our next character
while(nextChar <= ch2) { //test case
System.out.print(nextChar);
count++; //once we print a character, increment our count
if(count == numberPerLine) { //check if we reach our desired amount of characters
System.out.println();
count = 0; //once we print a new line, restart the count
}
nextChar = (char) (nextChar + 1); //get next character
}
}

Convert a letter to the corresponding letter on the opposite counting direction in the alphabet

I am self-studying Java and I am very at the beginning learning the basics. With below code I am trying to convert a letter to the corresponding letter on the opposite counting direction in the alphabet(i.e A to Z or Z to A etc.). It works for a single letter but not for a series of letters. How can I make it work with more than one letter? If you can use the simplest way it would be good as I am quite new in Java. I don't(know how to) export any built in classes etc.
Thank you.
class Turner{
int find(int fin, int mi,int ma,char ch[]){
int mid = (ma+mi)/2;
int x;
if(ch[mid]==fin)
return mid;
else if(fin<ch[mid])
return(find(fin, mi,mid-1,ch));
else
return x = find(fin,(mid+1),ma,ch);
}
}
class Turn {
public static void main(String args[]) throws java.io.IOException
{
Turner try1 = new Turner();
char arra[] = new char[26];
char arrb[] = new char[26];
int min = 0;
int max = arra.length;
char a = 'A';
char b = 'Z';
int i;
char letter;
for(i=0;i<26;i++)
{
arra[i]=a;
a++;
arrb[i]=b;
b--;
}
System.out.println("Enter a letter: ");
letter = (char)System.in.read();
System.out.print(arrb[try1.find(letter,min,max,arra)]);
}
}
Have you considered just doing some math?
letter = Character.toUpperCase((char)System.in.read());
System.out.print((char)('Z' - (letter - 'A'));
And it works for only one letter because you are not repeating the conversion procedure. The program reads one char, prints its opposite and then terminates.
All you have to do is to put the read and print code inside some sort of loop, so every time it runs it will promptly wait for the next letter.
while (true) {
letter = Character.toUpperCase((char)System.in.read());
if ((letter > 'Z') || (letter < 'A'))
break; // user inputted an invalid symbol, terminating the program
System.out.print((char)('Z' - (letter - 'A')));
}
If your function (they are called methods in java) works, good. Just put it in a while loop or otherwise call it when you need it.
boolean done = false;
while(!done){
System.out.println("Enter a letter (space to quit): ");
letter = (char)System.in.read();
if(letter == ' ') done = true;
else System.out.print(arrb[try1.find(letter,min,max,arra)]);
}
And Havenard is right, this can be written considerably more simply, with arithmetic on chars. For instance ch -'a' == 1 evaluates to true when ch is 'b'.
One other note: find and Turner aren't very descriptive names for what these things do. Before long it could get messy without simple and to the point naming.
A character has an equivalent numerical value. For "basic characters", this mapping is called ASCII table: http://www.asciitable.com/
Now, in java, you can convert a char into an int by casting. Example: int nValue=(int) 'a'.
Since there is a numerical value associated to 'a' and another one associated with 'z', you could use some simple math to solve your problem.
See:
int aNumericalValue = (int) 'a';
int zNumericalValue = (int) 'z';
char characterToConvert = ...;
int characterToConvertAsNumericalValue = (int) characterToConvert;
int resultCharacterAsNumericalValue = zNumericalValue - (characterToConvertAsNumericalValue - aNumericalValue);
char resultCharacter = (char) resultCharacterAsNumericalValue;
Or, you could write all of this as a single line of code:
char resultCharacter = (char) ((int) 'z' - ((int) characterToConvert - (int) 'a'));
And finally, if you are willing to hardcode some ASCII values:
char resultCharacter = (char) (122 - ((int) characterToConvert - 97));
Note that this is for lowercase letters. For caps, use 'A' (ascii 65), 'Z' (ascii 90).

Categories

Resources