My attempt at using a Caeser Cipher is failing on capital letters has incorrect results.
input: All-convoYs-9-be:Alert1. and rotation factor is 200
Correct output: Epp-gsrzsCw-3-fi:Epivx5.
My result:
_pp-gsrzs]w-3-fi:_pivx5.
String rotationalCipher(String input, int rotationFactor) {
StringBuilder sb = new StringBuilder();
char[] chars = input.toCharArray();
for(char c : chars){
if(Character.isLetter(c)){
int currentPos = c - 'a';
int newPos = (currentPos + rotationFactor) % 26;
char newCharacter = (char) ('a' + newPos);
sb.append(newCharacter);
}else if(Character.isDigit(c)){
String y = Character.toString(c);
int x = Integer.parseInt(translateNumber(y,rotationFactor));
sb.append(x);
}else {
sb.append(c);
}
}
return sb.toString();
}
String translateNumber(String oldNumber, int rotationFactor){
Integer n = Integer.parseInt(oldNumber);
int newNumber = n + rotationFactor;
if(newNumber > 10){
newNumber = newNumber % 10;
}
return String.valueOf(newNumber);
}
int verifyRotationFactor(int rotationFactor){
int max = 26;
int div = rotationFactor / max;
if(div > 1){
return div;
}
return rotationFactor;
}
I'm very new to this, not sure what I need to fix.
It seems like ASCII related problem to me. You should shift position of letter in an array that contains letters. In your way it shifts letters by ASCII order.
So
It finds C and replace it with "]"
It finds E and replace it with "_"
If it would find B, the program will return "\" eventually.
BECAUSE THERE IS NON-ALPHANUMERIC VALUES BETWEEN LETTERS IN ASCII
TABLE.
more info: https://www.fileformat.info/info/charset/UTF-16/list.html
In order to make cipher work better, you need an array to loop inside.
Related
I'm trying to solve Caesar's Cipher in Java but there's a twist to it. The input string has alphanumeric values and I am unable to solve. Here's what I've attempted so far:
String rotationalCipher(String input, int rotationFactor) {
// Write your code here
StringBuilder sb = new StringBuilder();
for(int i = 0; i < input.length(); i++) {
if(Character.isLowerCase(input.charAt(i))) {
char ch = (char)(((int)input.charAt(i) + rotationFactor - 97) % 26 + 97);
} else if (Character.isUpperCase(input.charAt(i))) {
char ch = (char)(((int)input.charAt(i) + rotationFactor - 65) % 26 + 65);
sb.append(ch);
} else {
char ch = (char)(((int)input.charAt(i) + rotationFactor - 48) % 10 + 48);
sb.append(ch);
}
}
return sb.toString();
}
What I'm trying to do is evaluate each case using its ASCII values but I don't seem to get the desired output. Am I using ASCII wrong? Thanks for your help!
Sample input/output:
input = Zebra-493?
rotationFactor = 3
output = Cheud-726?
You have two major problems.
You did not update StringBuilder with an append for lowercase transitions.
You need to handle digits specially using isDigit just like upper and lower case so that you can then ignore characters like - and ?
A couple of suggestions.
just assign ch when you first enter the loop and then use it throughout the loop. No need to keep typing in all the input stuff.
only append ch to the StringBuilder once near the end when you exit the if/else blocks.
Instead of numbers like 97 and 65 use 'a' and 'A'. Less likely to make mistakes that way.
Once you make those changes, your code works just fine.
Below code works for me-
String rotationalCipher(String input, int rotationFactor) {
// Write your code here
StringBuffer sb = new StringBuffer();
for (int i = 0; i < input.length(); i++) {
char x = input.charAt(i);
if (Character.isLowerCase(x)) {
char ch = (char) ((x + rotationFactor - 97) % 26 + 97);
sb.append(ch);
} else if (Character.isUpperCase(x)) {
char ch = (char) ((x + rotationFactor - 65) % 26 + 65);
sb.append(ch);
} else if (Character.isDigit(x)) {
char ch = (char) ((x + rotationFactor - 48) % 10 + 48);
sb.append(ch);
} else {
sb.append(x);
}
}
return sb.toString();
}
String rotationalCipher(String input, int rotationFactor) {
String output = "";
for(char a: input.toCharArray()){
if(Character.isAlphabetic(a)){
char startLetter = Character.isUpperCase(a) ? 'A' : 'a';
output += (char) ((a- startLetter + rotationFactor) % 26 + startLetter);
}
else if(Character.isDigit(a)){
output += (char) ((a + rotationFactor - 48) % 10 + 48);
}
else{
output += a;
}
}
return output;}
I have a problem with this exercise.
In this exercise I enter a word and a number. I have to use the ASCII table to encrypt the word.
If I enter the letter "a" and the number 3, the letter becomes "d".
If I enter the letter "z" and the number 2, the letter should become "b", but a symbol comes out.
Another problem is if I use an uppercase letter. If I enter the uppercase letter "Z" I'll still get a symbol.
Another problem is if I use the letters "aB" and the number -2 should come out "yZ", but symbols come out.
This is the exercise:
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String s, n="";
int N;
System.out.println("Insert a word");
s=in.next();
System.out.println("Insert a number");
N=in.nextInt();
n=uno(s, N);
System.out.println("That's the encrypted word: " + n);
}
public static String uno (String s, int N) {
String f, n="";
int c;
int length = s.length();
for (int i=0; i<length; i++) {
c = s.charAt(i);
c=c+N;
f = Character.toString((char)c);
n=n+f;
}
return n;
}
ASCII for z is 122. You add 2 to that. The ASCII for 124 is | symbol.
You need to check if your addition is going out of range (i.e. above 122).
Note: this won't work is N is greater than 26. Check the solution just below that implements modulo to handle that.
public static String uno (String s, int N) {
String f, n = "";
int c;
int length = s.length();
for (int i = 0; i < length; i++) {
c = s.charAt(i);
c = c + N;
if (c >= 122) {
c -= 26;
}
f = Character.toString((char) c);
n = n + f;
}
return n;
}
Side note: Never concatenate a string in a loop using +. It is very inefficient. Using StringBuilder.
Handle case sensitive letters concisely:
public static String uno (String s, int N) {
StringBuilder n = new StringBuilder();
int bound = s.length();
IntStream.range(0, bound).forEach(i -> {
char c = s.charAt(i);
n.append(Character.isUpperCase(c) ?
(char) ((c + N - 'A') % 26 + 'A') :
(char) ((c + N - 'a') % 26 + 'a'));
});
return n.toString();
}
Handling negative numbers:
public static String uno (String s, int N) {
StringBuilder n = new StringBuilder();
int bound = s.length();
IntStream.range(0, bound).forEach(i -> {
char c = s.charAt(i);
if (N > 0) {
n.append(Character.isUpperCase(c) ?
(char) ((c + N - 'A') % 26 + 'A') :
(char) ((c + N - 'a') % 26 + 'a'));
} else {
n.append((char) (c + N % 26 + 26));
}
});
return n.toString();
}
Check this comment for a good point on your naming conventions.
I am trying to create the addition portion of a vigenere cipher and need to add letters in the alphabet together, resulting in another letter from the alphabet. This must be the standard alphabet with not special characters. All 26 letters.
I can get the number associated with the alphabet number. for example A =0 B=1 ... z=25, So how would i be able to create string full of the letter equivalent of that number?
public String encrypt(String orig, String iv, String key) {
int i, j, result;
String cipherText = "";
int b = iv.length();
//loops through the entire set of chars
for (i = 0; i < text.length; i += b) {
//Splits the char into block the size of the IV block.
for (j = 0; j < b; j++) {
//checks to for first block. If so, begains with iv.
if (i == 0) {
//adding the iv to the block chars
char one = text[j], two = iv.charAt(j);
result = (((iv.charAt(j) - 'a') + (text[j] - 'a')) % 26);
//prints out test result.
System.out.println(one + " + " + (iv.charAt(j) - 'a') + "= " + result);
} else {
//block chainging, addition, with new key.
result = ((key.charAt(j) - 'a') + (text[j + i] - 'a')) % 26;
// System.out.println(result);
}
}
}
return cipherText;
}
I created a new method with a char array and all of the inputs were the alphabet. I called the method with the number in question and returned a char.
public char lookup(int num){
char[] alphabet = {'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'};
return alphabet[num];
}
Chars can automatically converted to ints.
For example try this:
final char aChar = 'a';
char bChar = aChar + 1;
char uChar = (char) (bChar + 19);
char qChar = (char) (uChar - 4);
System.out.println(aChar+" "+ bChar + " " + qChar + " " + uChar);
Since the numeric code of 'a' to 'z' are consecutive with the char type (UTF-16), you could simply use addition:
public char lookup(int num) {
return (char)('a' + num);
}
Because char + int will result in an int, we need to cast the type back to char.
I'm trying to create a loop which only returns letters. In my code, I get symbols that I don't want. How do I fix my loop so that when my integer is +3, it only gives me letters?
public static String caesarDecrypt(String encoded, int shift){
String decrypted = "";
for (int i = 0; i < encoded.length(); i++) {
char t = encoded.charAt(i);
if ((t <= 'a') && (t >= 'z')) {
t -= shift;
}
if (t > 'z') {
t += 26;
} else if ((t >= 'A') && (t <= 'Z')) {
t -= shift;
if (t > 'Z')
t += 26;
} else {
}
decrypted = decrypted + t;
}
}
You are subtracting the shift value from the letters. Therefore, the new letter can never be > 'z'. You should check if the it is < 'a' (or 'A', respectively).
StringBuilder decrypted = new StringBuilder(encoded.length());
for (int i = 0; i < encoded.length(); i++)
{
char t = encoded.charAt(i);
if ((t >= 'a') && (t <= 'z'))
{
t -= shift;
while (t < 'a')
{
t += 26;
}
}
else if ((t >= 'A') && (t <= 'Z'))
{
t -= shift;
while (t < 'A')
{
t += 26;
}
}
decrypted.append(t);
}
return decrypted.toString();
Also, you shouldn't be using String concatenation to generate the result. Learn about StringBuilder instead.
EDIT: To make sure the new letter is in the range 'a' .. 'z' for an arbitrary (positive) shift, you should use while instead of if.
I am not giving you exact code. But I can help you in logic:
Check whether you are reaching end points (a, A, z, Z) due to the shift.
If you exceed the end points either way, then compute the distance between end points and shifted t. Add/subtract/modulus (based on the end point) this distance to the other endpoint to get the exact letter.
Something like this? (Warning, untested)
public static String caesarDecrypt(String encoded, int shift) {
String decrypted = "";
for (int i = 0; i < encoded.length(); i++) {
char t = encoded.charAt(i).ToUpper();
decrypted = decrypted + decode(t, shift);
}
}
// call with uppercase ASCII letters, and a positive shift
function decode(char n, int shift)
{
if ((n < 'A') || (n > 'Z')) return ('-');
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var s = str.charAt(((n - 'A') + shift)%26);
return(s);
}
As you are naming your method caesarDecrypt (I assume you mean encrypt), I think you want a shift in the alphabet including wrapping around.
This code will do that for you:
public class Snippet {
public static void main(String[] args) {
System.out.println(caesarShift("This is a Fizzy test.", 5));
System.out.println(caesarShift("Ymnx nx f Kneed yjxy.", -5));
}
public static String caesarShift(String input, int shift) {
// making sure that shift is positive so that modulo works correctly
while (shift < 0)
shift += 26;
int l = input.length();
StringBuffer output = new StringBuffer();
for (int i = 0; i < l; i++) {
char c = input.charAt(i);
char newLetter = c;
if (c >= 'a' && c <= 'z') { // lowercase
newLetter = (char) ((c - 'a' + shift) % 26 + 'a'); // shift, wrap it and convert it back to char
} else if (c >= 'A' && c <= 'Z') { // uppercase
newLetter = (char) ((c - 'A' + shift) % 26 + 'A'); // shift, wrap it and convert it back to char
}
output.append(newLetter);
}
return output.toString();
}
}
This will handle lowercase and uppercase letters. Everything else will be left as it is (like spaces, punctuations, etc).
Please take some time to look at this code to understand how it works. I have put some comments to make it clearer. From your code I think you were a bit confused, so it is important that you understand this code very well. If you have questions, feel free to ask them.
This code
String start = "abcdefghijklmnopqrstuvwxyz";
String encrypted = caesarShift(start, 3);
String decrypted = caesarShift(encrypted, -3);
System.out.println("Start : " + start);
System.out.println("Encrypted : " + encrypted);
System.out.println("Decrypted : " + decrypted);
will give this result
Start : abcdefghijklmnopqrstuvwxyz
Encrypted : defghijklmnopqrstuvwxyzabc
Decrypted : abcdefghijklmnopqrstuvwxyz
String word = "ABCD";
StringBuffer str = new StringBuffer (word);
int counter = 0;
for (int ch = 0; ch < word.length(); ch ++)
{
int number = word.charAt(ch)- 'A' + 1;
str.setCharAt(counter, (char) number);
if (ch != word.length ()-1)
str.insert(counter +1, '-');
counter += 2;
}
System.out.println (str);
}
I want my output to be 1-2-3-4, so A = 1 and B= 2.... etc. We can assume that all the input are in upper case. But the my code produce random symbols. So how do I fix the code to produce 1-2-3-4 without re writing the whole thing?
You're only missing the conversion from int back to char. The line
str.setCharAt(counter, (char) number);
should be
str.setCharAt(counter, (char) ('0' + number));