How do I shift letters down in a loop - java

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

Related

Implementation of the Caesar cipher

I have to Implement a static public method named encodeCaesar in the class Functionality.java, which encodes a text using Caesar encryption and I am a complete novice in Java.
Signature: encodeCaesar(String s, int val) : String
The method gets a string value and an integer value as input parameters. The letters (characters) from the string value are to be shifted by the integer value. For simplicity, I can assume that there are only letters and no spaces, numbers or special characters.
The string value should be converted to lower case before the encryption is performed. The method should return a string where each letter has been moved according to the specified integer value.
Example: encodeCaesar("Ac",3) returns "df". If the given integer value is less than 0 or greater than 26, an empty string should be returned.
public class Functionality {
public static void main(String[] args) {
}
public static String encodeCaesar(String s, int val) {
char[] newString = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
int newChar = newString[i] + val + 26;
// Handle uppercase letters
while (Character.isUpperCase(newString[i]) && newChar >= 65 + 26) {
newChar -= 26;
}
// Handle lowecase letters
while (Character.isLowerCase(newString[i]) && newChar >= 97 + 26) {
newChar -= 26;
}
newString[i] = (char) (newChar);
}
return String.valueOf(newString);
}
}
My problem is that in return it give me only true or false. How can I solve this: The method should return a string where each character has been moved according to the specified integer value.
The following code snippet addresses some minor issues:
non-letter characters (if any) remain unchanged by the cipher
while loop replaced with if
use modulo operator to wrap values over z
public static String encodeCaesar(String s, int val) {
char[] newString = s.toLowerCase().toCharArray();
for (int i = 0; i < newString.length; i++) {
char newChar = newString[i];
if (newChar >= 'a' && newChar <= 'z') {
newString[i] = (char) ('a' + (newChar + val - 'a') % 26);
}
}
return new String(newString); // String.valueOf calls it anyway
}
Comparison:
System.out.println("encode: " + encodeCaesar("Viva Caesar! Morituri te salutant!", 3));
System.out.println("caesar: " + caesar("Viva Caesar! Morituri te salutant!", 3));
Output:
encode: ylyd fdhvdu! prulwxul wh vdoxwdqw!
caesar: ylyd=fdhvdu>=prulwxul=wh=vdoxwdqw>
public static String caesar(String s, int val) {
char[] newString = s.toLowerCase().toCharArray();
for (int i = 0; i < s.length(); i++) {
int newChar = newString[i] + val + 26;
// Handle lowercase letters
while (Character.isLowerCase(newString[i]) && newChar >= 97 + 26) {
newChar -= 26;
}
newString[i] = (char) (newChar);
}
return String.valueOf(newString);
}
I solved the problem.
You can use String.codePoints method to iterate over int values of the characters of this string, and shift them by a given value:
public static String encodeCaesar(String s, int val) {
if (val < 0 || val > 26) return "";
return s.codePoints()
// Stream<Character>
.mapToObj(i -> (char) i)
// convert to lowercase
.map(Character::toLowerCase)
// filter out non-letters
.filter(ch -> ch >= 'a' && ch <= 'z')
// if a letter should be shifted
// outside the alphabetical range,
// then move it before the beginning
.map(ch -> ch + val > 'z' ? ch - 'z' + 'a' - 1 : ch)
// shift letter by a given value
.map(ch -> ch + val)
// each character as a single string
.map(Character::toString)
// join characters into one string
.collect(Collectors.joining());
}
public static void main(String[] args) {
System.out.println(encodeCaesar("Ac", 3)); // df
System.out.println(encodeCaesar("YZx 32*d", 3)); // bcag
}
See also: Replace non ASCII character from string

Alphanumeric Caesar's Cipher in Java

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;}

Java- getting wrong output

Here's my code that I've written :
public String binary(String s)
{
String[] a = {
"0000","0001","0010","0011","0100","0101","0110","0111",
"1000","1001","1010","1011","1100","1101","1110","1111"
};
String k = "";
for(int i = 0; i <= s.length() - 1; i++)
{
if (s.charAt(i) == 'a') { k += a[10]; }
else if (s.charAt(i) == 'b') { k += a[11]; }
else if (s.charAt(i) == 'c') { k += a[12]; }
else if (s.charAt(i) == 'd') { k += a[13]; }
else if (s.charAt(i) == 'e') { k += a[14]; }
else if (s.charAt(i) == 'f') { k += a[15]; }
else { k += a[i]; }
}
return k;
}
I am getting output as a[0-9] = 0000. How can I fix this? What am I doing wrong?
The problem is with use of a[i]. It is a logical error. Because i is loop variable which indicates the current index in s String. But you are using it to indexing it in variable a. So, i variable is use incorrectly here.
Following is corrected (and a bit optimized) code. See it working here:
public class HexaDecimal
{
public String binary(String s)
{
String[] a= {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};
String k="";
for(int i=0;i<s.length();i++)
{
char ch = Character.toUpperCase(s.charAt(i));
if(ch>='A' && ch <= 'F') k+= a[ch - 'A' + 10];
else k+= a[ch - '0'];
}
return k;
}
}
Replace k+=a[i]; with k+=a[s.charAt(i) - '0'];
You're using your string index loop variable as an index into a rather than the character at that location in the string.
You need to do - '0' to convert from unicode codepoint to the value it represents as an ASCII digit (which I assume you want to use here)
Your last else does the incorrect calculation. It does not take into consideration what is inputted, only the position. You want it to be
else {
k += a[s.charAt(i) - '0'];
}
There are easier ways to get the binary representation of hexadecimals, and you probably also want to check the input that it does not contain anything else than 0-9 or a-f.
You can change the for loop to this:
for(int i=0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c >= '0' && c <= '9') k += a[c - '0'];
else if (c >= 'a' && c <= 'f') k += a[c - 'a' + 10];
else if (c >= 'A' && c <= 'F') k += a[c - 'A' + 10];
else throw new InvalidArgumentException(s);
}
This is a lot simpler and self-explanatory, at least in my opinion. Handles digits, uppercase and lowercase letters, and fails in an expected way on bad input.

String to Unicode in Java

I have a large string I need to convert all the non alphanumeric chars to unicode
For example
Input string : abc12/dad-das/das_sdj
Output String : abc12:002Fdad:002Ddas:002Fdas:002Fsdj
Currently I am using this function
for (char c : str.toCharArray()) {
System.out.printf(":%04X \n", (int) c);
}
Is there a better way to do it ?
Here are two ways to do it:
// Looping over string characters
private static String convert(String input) {
StringBuilder buf = new StringBuilder(input.length() + 16);
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
buf.append(c);
else
buf.append(String.format(":%04X", (int) c));
}
return buf.toString();
}
// Using regular expression
private static String convert(String input) {
StringBuffer buf = new StringBuffer(input.length() + 16);
Matcher m = Pattern.compile("[^a-zA-Z0-9]").matcher(input);
while (m.find())
m.appendReplacement(buf, String.format(":%04X", (int) m.group().charAt(0)));
return m.appendTail(buf).toString();
}
Test
System.out.println(convert("abc12/dad-das/das_sdj"));
Output
abc12:002Fdad:002Ddas:002Fdas:005Fsdj

How to use ASCII in array

I want to write a program that takes a string text, counts the appearances of every letter in English and stores them inside an array.and print the result like this:
java test abaacc
a:***
b:*
c:**
* - As many time the letter appears.
public static void main (String[] args) {
String input = args[0];
char [] letters = input.toCharArray();
System.out.println((char)97);
String a = "a:";
for (int i=0; i<letters.length; i++) {
int temp = letters[i];
i = i+97;
if (temp == (char)i) {
temp = temp + "*";
}
i = i - 97;
}
System.out.println(temp);
}
Writing (char)97 makes the code less readable. Use 'a'.
As 3kings said in a comment, you need an array of 26 counters, one for each letter of the English alphabet.
Your code should also handle both uppercase and lowercase letters.
private static void printLetterCounts(String text) {
int[] letterCount = new int[26];
for (char c : text.toCharArray())
if (c >= 'a' && c <= 'z')
letterCount[c - 'a']++;
else if (c >= 'A' && c <= 'Z')
letterCount[c - 'A']++;
for (int i = 0; i < 26; i++)
if (letterCount[i] > 0) {
char[] stars = new char[letterCount[i]];
Arrays.fill(stars, '*');
System.out.println((char)('a' + i) + ":" + new String(stars));
}
}
Test
printLetterCounts("abaacc");
System.out.println();
printLetterCounts("This is a test of the letter counting logic");
Output
a:***
b:*
c:**
a:*
c:**
e:****
f:*
g:**
h:**
i:****
l:**
n:**
o:***
r:*
s:***
t:*******
u:*

Categories