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;}
Related
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.
I hope this isn't too much of a stupid question, I have looked on 5 different pages of Google results but haven't been able to find anything on this.
What I need to do is convert a string that contains all Hex characters into ASCII for example
String fileName =
75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000
Every way I have seen makes it seems like you have to put it into an array first. Is there no way to loop through each two and convert them?
Just use a for loop to go through each couple of characters in the string, convert them to a character and then whack the character on the end of a string builder:
String hex = "75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000";
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
System.out.println(output);
Or (Java 8+) if you're feeling particularly uncouth, use the infamous "fixed width string split" hack to enable you to do a one-liner with streams instead:
System.out.println(Arrays
.stream(hex.split("(?<=\\G..)")) //https://stackoverflow.com/questions/2297347/splitting-a-string-at-every-n-th-character
.map(s -> Character.toString((char)Integer.parseInt(s, 16)))
.collect(Collectors.joining()));
Either way, this gives a few lines starting with the following:
uTorrent\Completed\nfsuc_ost_by_mustang\Pendulum-9,000 Miles.mp3
Hmmm... :-)
Easiest way to do it with javax.xml.bind.DatatypeConverter:
String hex = "75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000";
byte[] s = DatatypeConverter.parseHexBinary(hex);
System.out.println(new String(s));
String hexToAscii(String s) {
int n = s.length();
StringBuilder sb = new StringBuilder(n / 2);
for (int i = 0; i < n; i += 2) {
char a = s.charAt(i);
char b = s.charAt(i + 1);
sb.append((char) ((hexToInt(a) << 4) | hexToInt(b)));
}
return sb.toString();
}
private static int hexToInt(char ch) {
if ('a' <= ch && ch <= 'f') { return ch - 'a' + 10; }
if ('A' <= ch && ch <= 'F') { return ch - 'A' + 10; }
if ('0' <= ch && ch <= '9') { return ch - '0'; }
throw new IllegalArgumentException(String.valueOf(ch));
}
Check out Convert a string representation of a hex dump to a byte array using Java?
Disregarding encoding, etc. you can do new String (hexStringToByteArray("75546..."));
So as I understand it, you need to pull out successive pairs of hex digits, then decode that 2-digit hex number and take the corresponding char:
String s = "...";
StringBuilder sb = new StringBuilder(s.length() / 2);
for (int i = 0; i < s.length(); i+=2) {
String hex = "" + s.charAt(i) + s.charAt(i+1);
int ival = Integer.parseInt(hex, 16);
sb.append((char) ival);
}
String string = sb.toString();
//%%%%%%%%%%%%%%%%%%%%%% HEX to ASCII %%%%%%%%%%%%%%%%%%%%%%
public String convertHexToString(String hex){
String ascii="";
String str;
// Convert hex string to "even" length
int rmd,length;
length=hex.length();
rmd =length % 2;
if(rmd==1)
hex = "0"+hex;
// split into two characters
for( int i=0; i<hex.length()-1; i+=2 ){
//split the hex into pairs
String pair = hex.substring(i, (i + 2));
//convert hex to decimal
int dec = Integer.parseInt(pair, 16);
str=CheckCode(dec);
ascii=ascii+" "+str;
}
return ascii;
}
public String CheckCode(int dec){
String str;
//convert the decimal to character
str = Character.toString((char) dec);
if(dec<32 || dec>126 && dec<161)
str="n/a";
return str;
}
To this case, I have a hexadecimal data format into an int array and I want to convert them on String.
int[] encodeHex = new int[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f }; // Hello encode
for (int i = 0; i < encodeHex.length; i++) {
System.out.print((char) (encodeHex[i]));
}
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));