Decoding sentences in Java using arrays - java

So I am doing some practice problems for an upcoming exam and one of the problems is posing a bit of a challenge to me.
The problem states that our code should take a string that has been encoded and decode it. It must work as follows:
Each letter is decoded using the letter immediately before it in the alphabet ("b" becomes "a", "c" becomes "b" ect.)
"a" becomes "z".
each digit works the same way, 8 becomes 7, 5 becomes 4.
0 becomes 9.
characters neither letters nor digits are unchanged.
THE ONLY JAVA METHOD I CAN USE IS IO
Ex:
NFFU NF BU 23 JO UIF CFMM UPXFS
meet me at 12 in the bell tower
heres my current code, i cannot decide whether to use for loops or not. TBH I am not really sure how to tackle this.
public class prb1 {
public static void main(String[] args) {
char letter[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int num[]={0,1,2,3,4,5,6,7,8,9};
System.out.println("Enter Message");
String mssg=IO.readString();
for(char i=0; i<letter.length; i++){
System.out.print(letter[i]--);}
for(int j=0; j<num.length; j++){
System.out.print(num[j]--);
}
}
}

The basic is like this. But this doesn't account yet for the a => z conversion.
String cypher ="ABCDEF";
String plain = "";
for (char c : cypher.toCharArray())
plain += (char) (c - 1);
System.out.println(plain);
With the modulo A => Z, it looks like this:
int A = 'A';
plain += (char) (((c - A - 1 + 26) % 26) + A);
The +26 is needed because java says -1 % 26 == -1 instead of 25.
So this just works for A-Z, but you can easily modify it to work for wider ranges.

You can use a loop to iterate through each character of the message and subtract one from its ascii code if its not a space, an a, or an A:
String message = "NFFU NF BU 23 JO UIF CFMM UPXFS";
String result = "";
for (char thisChar : message.toCharArray()) {
if (thisChar == ' ') {
result += " ";
} else if(thisChar == 'a') {
result += 'z';
} else if (thisChar == 'A') {
result += 'Z';
} else
result += (char)(thisChar - 1);
}
}
System.out.println(result);
Alternatively, you could do:
String message = "NFFU NF BU 23 JO UIF CFMM UPXFS";
String result = "";
for (int i = 0; i < message.length(); i ++) {
char thisChar = message.charAt(i);
if (thisChar == ' ') {
result += " ";
} else if(thisChar == 'a') {
result += 'z';
} else if (thisChar == 'A') {
result += 'Z';
} else
result += (char)(thisChar - 1);
}
}
System.out.println(result);
Technically,
else if(thisChar == 'a') {
result += 'z';
} else if (thisChar == 'A') {
result += 'Z';
}
could be shortened to:
else if(thisChar == 'a' || thisChar == 'A') {
result += (char)(thisChar + 25);
}

Related

Adding/Subtracting big number to and from a character

For case #1, adding 2 to 'a' gives us 'c'.
How can I write a program so that adding 2 to 'z' gives 'b' as an output and subtracting 3 from 'a' gives 'x' as an output?
In other words, I want only alphabet character as an output. No matter how big number you are adding or subtracting to and from the character, I always expect the output between a and z inclusive.
case #1
public void addNumberToCharacter{
char character = 'a' + 2;
System.out.println(character); // 'c'
}
case #2
public void addNumberToCharacter{
char character = 'z' + 2;
System.out.println(character); // 'b'
}
case #3
public void addNumberToCharacter{
char character = 'a' - 3;
System.out.println(character); // 'x'
}
To handle two cases you might also require:
uppercase and lowercase;
adding/subtracting number whose absolute value is bigger than 26;
And here is the method you can refer to:
private static void addNumToChar(int a, char c0) {
char c = 'a';
if(Character.isUpperCase(c0)) {
c = 'A';
}
while (a < 0) a += 26;
char c1 = (char) (c + (c0 - c + a) % 26);
System.out.println(c1);
}
Run the test as follows:
addNumToChar(2, 'B'); // D
addNumToChar(2, 'b'); // d
addNumToChar(261, 'B'); // C
addNumToChar(261, 'b'); // c
addNumToChar(-2, 'B'); // Z
addNumToChar(-2, 'b'); // z
addNumToChar(-261, 'B'); // A
addNumToChar(-261, 'b'); // a
After you add or subtract, correct with:
character = (character + 26 - 'a')%26 + 'a';
Java's x%y operator gives the remainder from integer division of x by y. Subtracting 'a' gives the offset from the start of the lowercase alphabet, and then adding 26 guarantees a positive sum, provided you didn't add an offset less than -26 or subtract more than +26.
public char number(int num, char c){ // -- num =29, char= 'd'
int n = c - 96 ; // n = 4
n = n+(num%26); // n = 4 + 3 = 7
if(n > 26){ return (char)(n-26); } // doesnot follow
else if(n < 0){ return (char)(n+26); } // doesnot follow
else { return (char)(n); } // return g
}
You can try this method. It can handle positive as well as negative number.
use that one :-
public static void main(String[] args) {
char c= 'a' - 1;
if(!(c>=97 && c<=122)) {
if(c>=123)
c= (char) (c-26);
else
c= (char) (c+26);
}
System.out.println(c);
}

Incremented by a value x but it gets incremented by value x-1

I am implementing an Algorithm where when user gives input string, every character in string (if it is alphabet) should be incremented by value given(here rotator). I am playing with this code for 2 hr but can't figure out why when i increment by value rotator, it gets incremented by rotator-1.
public class Solution {
public static void main(String[] args) {
/* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
Scanner in = new Scanner(System.in);
int length = in.nextInt();
String input = in.next();
int nextvalue = 0;
int temp = 0;
char array[] = input.toCharArray();
int rotator = in.nextInt();
for(int i = 0; i < length; i++){
if((array[i] >= 'a' && array[i] <= 'z') || (array[i] >= 'A' && array[i] <= 'Z')){
nextvalue = (int)array[i] + rotator;
array[i] = (char)nextvalue;
if((int)array[i] > (int)'z'){
temp = (int)array[i] - (int)'z';
nextvalue = (int)'a' + temp -1;
array[i] = (char)nextvalue;
}
else if((int)array[i] > (int)'Z'){
temp = (int)array[i] - (int)'Z';
nextvalue = (int)'Z' + temp -1;
array[i] = (char)nextvalue;
}
}
}
System.out.println(array);
}
}
Inside first if there are two if statements to handle(Overflow condition) if letter is > z or >Z. Now if I Remove those two statements everything except overflow condition is correctly printed
(without overflow condition)
Sample I/P :
11 <- String length
middle-Outz
2 <- rotator
Sample O/P :
okffng-Qwv| <- Overflow condition not handled
(with overflow condition)
Sample I/P :
11
middle-Outz
2
Sample O/P :
njeemf-Qvub <- Overflow handled but everything else incremented by rotator - 1 except 'Q'
Why is this happening? I also checked using print statement in inner if condition , it executes only one time for this input since there is only one overflow condition.
Help/Suggestion appreciated.Thanks.
I think the easiest way to handle the overflow cases is to use the modulus operator to let the character wrap-around any number of times to land in the current logical position. Something like this should work:
for (int i=0; i < length; i++) {
if (array[i] >= 'a' && array[i] <= 'z') {
int currDiff = (int)array[i] - (int)'a';
int newPos = (int)'a' + ((rotator + currDiff) % 26);
array[i] = (char)newPos;
}
else if (array[i] >= 'A' && array[i] <= 'Z') {
int currDiff = (int)array[i] - (int)'A';
int newPos = (int)'A' + ((rotator + currDiff) % 26);
array[i] = (char)newPos;
}
}
I tested this code using an input string of abcdefg and a rotator value of 51, which returned zabcdef. This is expected, because we rotated one step short of two complete rounds. Hence, the a landed on z, after one complete rotation, and the following characters followed suit.
Note that there is a much nicer way of handling the calculus of character positions here, but this answer stays true to the way you were doing it in your original question.
Final note:
The modulus operator % returns the remainder of the division of the number which preceeds it and proceeds it. In the solution I gave above, I take the effective rotator % 26. Here, the effective rotator is the current distance of the letter from either a or A plus however many steps we want to rotate. By taking this number mod 26, we always will end up with a number between 0 and 25. Hence, we will always take between 0 and 25 steps from a or A, which is the behavior you want in your program.
Because you are modifying it twice in your loop.
for(int i = 0; i < length; i++){
if((array[i] >= 'a' && array[i] <= 'z') || (array[i] >= 'A' && array[i] <= 'Z')){
nextvalue = (int)array[i] + rotator;
array[i] = (char)nextvalue; //<-- modifies from m to o
if((int)array[i] > (int)'z'){
temp = (int)array[i] - (int)'z';
nextvalue = (int)'a' + temp -1;
array[i] = (char)nextvalue;
}
else if((int)array[i] > (int)'Z'){
temp = (int)array[i] - (int)'Z';
nextvalue = (int)'Z' + temp -1;
array[i] = (char)nextvalue; //<--modifies again from o to n
}
}
}
The mistake is in this line:
if ((int) array[i] > (int) 'Z') {
You have to keep in mind that lowercase letters come "after" uppercase letters: 'Z' is represented by 90, and (for example) 'j ' is represented by 106 (for more info see this). The reason why 'Q' isn't affected by this mistake is because it is also a capital letter, and thus has a smaller decimal representation than 'Z'.
To fix this, you have to replace the line of code above with something along the lines of this:
if ((int) array[i] > (int) 'Z' && (int) array[i] <= (int) 'Z' + rotator) {
Instead of
nextvalue = (int)'Z' + temp -1;
Shouldn't it be
nextvalue = (int)'A' + temp -1;

Vigenere Cipher output

I was looking at the Vigene Ciphere source code provided on http://rosettacode.org/wiki/Vigen%C3%A8re_cipher#Java. I tried testing out the program myself, and it wasn't outputting the values I expect based on vigene. For example 'dog' being the word and 'bob' being the key I would expect this to be encrypted to 'ech', but is 'qot' instead.
public static void main(String[] args) {
String key = "bob";
String ori = "dog";
String enc = encrypt(ori, key);
System.out.println(enc);
}
static String encrypt(String text, final String key) {
String res = "";
text = text.toLowerCase();
for (int i = 0, j = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c < 'a' || c > 'z') continue;
res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A');
j = ++j % key.length();
}
return res;
}
However the output is different. Is this because my understanding of the cipher is incorrect or this has taken a different approach to the well known vigenere cipher.
As what was already pointed out by the user, you should change the line to:
res += (char)((c + key.charAt(j) - 2 * 'a') % 26 + 'a');
Alternatively, you can change this:
if (c < 'a' || c > 'z') continue;
to this:
if (c < 'A' || c > 'Z') continue;
Just ensure when you convert the ASCII back to letters, you are using the correct ASCII value (i.e. 65 (A) for uppercase, 97 (a) for lowercase).
Because you are setting your text to encrypt to lowercase, try changing these character literals to lowercase as well:
res += (char)((c + key.charAt(j) - 2 * 'a') % 26 + 'a');
When casting an int to a char, you have to take into account that the integer value of 'a' is not equal to 'A'. Because you are checking that your current character is between 'a' and 'z' (as you have set it to lowercase), you should also have an output in lowercase as well.

Base64.encode(bytearray, Base64.DEFAULT) result of this method will add 10 at last item

When i encode my byte array using Base64.encode(bytearray, Base64.DEFAULT) so result of this method will add 10 at last item in the resulting byte array and when i converting this resulting byte array into string than 10 will convert into \n(line feed) at the end
please let me know why the \n will append at the end
below is the code that will convert the string into byte array
int inLength = hexValue.length();
int i, o = 0;
long outByte = 0;
byte[] outBytes = new byte[(inLength / 2)];
for (i = 0; i < inLength; i++) {
char c = hexValue.charAt(i);
int value = -1;
if (c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = 10 + (c - 'A');
else if (c >= 'a' && c <= 'f')
value = 10 + (c - 'a');
if (value >= 0) {
if (i % 2 == 1) {
outBytes[o++] = (byte) ((outByte << 4) | value);
outByte = 0;
} else {
outByte = value;
}
} else {
if (o != 0)
break;
}
}
return outBytes;
I can't comment right now so i had to leave a reply.
Is this code written by you? or Someone else?
For Base64 encoding, byte are processed in blocks of 3 bytes at a time. If the length of the array is not a multiple of three then either one or two '0' zero bytes is appended to make full block.
And why are you writing your own logic where there are some API available to do the work for you?
Update: I just run the code again with help of API.
Input String: 51b034267f00000144495444
And
Corresponding Base64 encoded String: NTFiMDM0MjY3ZjAwMDAwMTQ0NDk1NDQ0
Simply put, 3 bytes will result in 4 plain text encoded bytes.

The error about string encryption scheduling : (char) (ch + key) % 26

Problem one: Here are two code spinner. Code A runs wrong. But I do not know what is wrong.
Problem two: code B is right.but I do not understand why it need to delete 'A’. then add 'A' after fmod. What is the effect about 'A'? Why it has the error after delete?
Code A (ch + key) % 26 )
Code B ('A' + ((ch -'A' + key) % 26))
public void run() {
setFont("Arial-PLAIN-24");
String line = readLine ("Enter line: ");
int key = readInt ("Enter key: ");
String siphertext = encryptCaesar(line , key);
println("The result is: " + siphertext);
String newplain = encryptCaesar(siphertext , -key);
println("newplain:" + newplain);
}
private String encryptCaesar(String str , int key){
if(key < 0){
key = 26 - ( -key % 26 );
}
String result = "";
for(int i = 0; i < str.length(); i++){
char ch = str.charAt(i);
result += encryptChar(ch,key);
}
return result;
}
private char encryptChar(char ch, int key){
if(Character.isUpperCase(ch)){
return ( (char) ('A' + ((ch -'A' + key) % 26)) );
}
return ch;
}
'A' is added to make sure the result of "encryptChar" method, is a valid character in ASCII range 64 to 90, which is A (CAPITAL) to Z (CAPITAL). Refer the ASCII table here.
In your code subtracting of 'A' can also be ignored. That is the below will also work,
('A' + ((ch + key) % 26))
15.7.3 Remainder Operator %
...
It follows from this rule that the result of the remainder operation
can be negative only if the dividend is negative, and can be positive
only if the dividend is positive.
An example is then provided:
int e = (-5)%3; // -2
int f = (-5)/3; // -1
System.out.println("(-5)%3 produces " + e +
" (note that (-5)/3 produces " + f + ")");
If the result of ((ch -'A' + key) % 26)) is negative, then wouldn't the result of (char) ('A' + ((ch -'A' + key) % 26)) be some non-alphabet character? Perhaps you need to add 26 to any negative values or find the absolute value, so that they're positive and result in actual alphabet characters.

Categories

Resources