Essentially, I am confused on the purpose of this code and what it does ( cAlphabet = (char)(cAlphabet - 'a' + 'z' + 1); ), in this encryption code, could someone please explain how this works thanks!
System.out.println(" Input the ciphertext message : ");
String ciphertext = sc.nextLine();
System.out.println(" Enter the shift value : ");
int shift = sc.nextInt();
String decryptMessage = "";
for (int i = 0; i < ciphertext.length(); i++)
{
// Shift one character at a time
char alphabet = ciphertext.charAt(i);
// if alphabet lies between a and z
if (alphabet >= 'a' && alphabet <= 'z')
{
// shift alphabet
alphabet = (char)(alphabet + shift);
// shift alphabet less than 'a'
if (cAlphabet < 'a')
{
//reshift to starting position
cAlphabet = (char)(cAlphabet - 'a' +'z' + 1);
}
cAlphabet = (char)(cAlphabet - 'a' + 'z' + 1);
When you make some operations(sum, minus, etc) with Char it wiil use numeric code of character. So you will get new numeric code and convert it back to the character.
this is almost the same as cAlphabet = (char)(cAlphabet - 219 + 97 + 1);
Related
I need to build a Caesar cipher that only encrypts letters, but no special characters. My concept was, to compare the input char[] with two alphabet char[]. If there is no match in a char, the char should be added to the String without being changed. The problem is that the not-changed char will be added to the String until the the for-loop ends. How do I fix this?
public static String encrypt(String text, int number) {
String str = "";
char[] chars = text.toCharArray();
char[] al = "abcdefghijklmnopqrstuvwxyz".toCharArray();
char[] ab = "abcdefghijklmnopqrstuvwxyz".toUpperCase().toCharArray();
for (char c : chars) {
boolean match = false;
for (int i = 1; i < chars.length - 1; i++) {
for (int k = 0; (k < al.length || k < ab.length) && !match; k++) {
match = (c == al[k] || c == ab[k]);
if (match) {
c += number;
str += c;
}
}
if (!match) {
str += c;
}
}
}
return str;
}
I already tried to put the case for not changing the string within the other for-loop, but it will be added until the for-loop has reached it's end.
I would tackle the problem by iterating through the String and considering the possible cases for each letter
Uppercase Letter
Lowercase Letter
Special Character
public static String encrypt(String text, int number) {
//String to hold our return value
String toReturn = "";
//Iterate across the string at each character
for (char c : text.toCharArray()){
if (Character.isUpperCase(c)){
/* If uppercase, add number to the character
If the character plus number is more than 90,
subtract 25 [uppercase letters have ASCII 65 to 90] */
toReturn += c + number > 90 ? (char)(c + number - 25) : (char)(c + number);
} else if (Character.isLowerCase(c)){
/* If lowercase, add number to the character
If the character plus number is more than 122,
subtract 25 [uppercase letters have ASCII 97 to 122] */
toReturn += c + number > 122 ? (char)(c + number - 25) : (char)(c + number);
} else {
// For other characters, just add it onto the return string
toReturn += c;
}
}
return toReturn;
}
Explanation of Code
You might be wondering what the following code does
toReturn += c + number > 90 ? (char)(c + number - 25) : (char)(c + number)
The structure is
toReturn += CONDITION ? A : B
It basically reads as
IF CONDITION IS TRUE, toReturn += A, ELSE toReturn += B
The CONDITION is simply c + number > 90 since we want to make sure that we are sticking with uppercase letters only
When this is true (A), we subtract 25 from c + number, otherwise (B) we just keep it as c + number (B)
We then cast this value into a char since it is initially an int
I write a func of Caesar Cipher.
So after I shift a sentence, I want also shift back to the original sentence.
For now it works only for one direction, when I shift with natural positive number, but when I try to do this with negative number, it goes on to value less than 97 of ascii lowercase letters.
I give an example:
word: java
key = 10
output: tkfk
Now I want to shift back, to restore my word from tkfk to java.
key = -10
output: ja\a
Instead of v it put \
I know its happens couse from f to minus 10 from ascii table is the letter '\' and I want the letter v.
I think I need to manipulate this line, but I dont know how, I'm a little bit stuck and I don't have an idea what to do.
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97)
My method: (little bit long)
public static void MakeCipherText(String[] text, int key) {
int index =0;
if (key > 0) {
if( text[index] == null || text[index].equals("")) {
System.out.println("No sentences to fix capital letters.");
} else {
while(text[index] != null && !text[index].equals("")) { // only if we have sentence in array or array not contain empty sentence we go through loop
String chiPstr = "";
for(int i=0; i<text[index].length(); i++) {//we work in every itration on 1 sentence (1 index of str array)
if(Character.isLowerCase(text[index].charAt(i))) {//if we have lower letter than:
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97); //we put asci value + Cipher value
chiPstr = chiPstr + ch; //each time we add to the new sentece the result
} else if(Character.isUpperCase(text[index].charAt(i))) {//same thing like here, but its work on uppercase letters.
char ch = (char) (((int) text[index].charAt(i) + key-65) % 26+65);
chiPstr = chiPstr + ch;
}else {// if we have space, or other characters that is no a letter, we just put him as is in a sentence.
chiPstr = chiPstr + text[index].charAt(i);
}
}
text[index] = chiPstr;
index ++;
}
}
} else { // key is negetive number
if( text[index] == null || text[index].equals("")) {
System.out.println("No sentences to fix capital letters.");
} else {
while(text[index] != null && !text[index].equals("")) { // only if we have sentence in array or array not contain empty sentence we go through loop
String chiPstr = "";
for(int i=0; i<text[index].length(); i++) {//we work in evry itration on 1 sentence (1 index of str array)
if(Character.isLowerCase(text[index].charAt(i))) {//if we have lower letter than:
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97); //we put asci value + Cipher value
chiPstr = chiPstr + ch; //each time we add to the new sentece the result
} else if(Character.isUpperCase(text[index].charAt(i))) {//same thing like here, but its work on uppercase letters.
char ch = (char) (((int) text[index].charAt(i) + key-65) % 26+65);
chiPstr = chiPstr + ch;
}else {// if we have space, or other characters that is no a letter, we just put him as is in a sentence.
chiPstr = chiPstr + text[index].charAt(i);
}
}
text[index] = chiPstr;
index ++;
}
}
}
}
Any suggestion?
As the comments suggest you should really check your code again this will also help you to be a better programmer. But anyway you think too complicated.
If you check your else part that is the exact copy of the if part. And that is no wonder. To decode Caesar cipher you encode it basically again with the right key to encode.
For example:
If you encode it with A => B or in this example with 1:
test--> uftu
so how can we decode uftu back?
When we shift it with B=>A or in this case with 25.
uftu --> test
So in your requirement you want if you put -1 that you decode text that was encoded with 1 before.
So basically we have to find a method to map -1 to 25, -2 to 24 and so on.
And the key function is: modulo
-2 % 26 => 24
-1 % 26 => 25
...
In addition you can even now put numbers bigger than 26 because:
500 % 26 => 6
-500 % 26 => 20
and because 2 % 26 => 2 you don't even need that if clause. Your code looks like this in the end:
public static void MakeCipherText(String[] text, int key) {
int index =0;
key = (((key % 26) + 26) % 26); // See below for explanation of this weird modulo
if( text[index] == null || text[index].equals("")) {
System.out.println("No sentences to fix capital letters.");
} else {
while(text[index] != null && !text[index].equals("")) { // only if we have sentence in array or array not contain empty sentence we go through loop
String chiPstr = "";
for(int i=0; i<text[index].length(); i++) {//we work in every itration on 1 sentence (1 index of str array)
if(Character.isLowerCase(text[index].charAt(i))) {//if we have lower letter than:
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97); //we put asci value + Cipher value
chiPstr = chiPstr + ch; //each time we add to the new sentece the result
} else if(Character.isUpperCase(text[index].charAt(i))) {//same thing like here, but its work on uppercase letters.
char ch = (char) (((int) text[index].charAt(i) + key-65) % 26+65);
chiPstr = chiPstr + ch;
}else {// if we have space, or other characters that is no a letter, we just put him as is in a sentence.
chiPstr = chiPstr + text[index].charAt(i);
}
}
text[index] = chiPstr;
index ++;
}
}
}
Never forget to use functions and don't use duplicate code. Bad style and error prone. The solution is quite easy if you think it through.
Information weird modulo function
You see I use a weird modulo function. Because in Java % don't calculate the modulo but the remainder. (Different then in Python).
So to get the "true" modulo in Java we have to use this weird trick:
Reference: What's the difference between “mod” and “remainder”?
key = (((key % 26) + 26) % 26);
I can't figure out how to perform this for both lowercase and uppercase. The Ascii value that I'm changing is being shifted by a randomly generated integer between 3 and 7. The purpose of the code is to produce a random credit card number.
char character3 = lastName.charAt(0);
int ascii3 = (int) character3;
char character4 = lastName.charAt(firstName.length()-1);
int ascii4 = (int) character4;
//testing output
System.out.println(ascii1 + " " + ascii2 + " " + ascii3 + " " + ascii4 + " ");
int Ascii1 = ascii1 + finalRandom;
int Ascii2 = ascii2 + finalRandom;
int Ascii3 = ascii3 + finalRandom;
int Ascii4 = ascii4 + finalRandom;
//Wrapping value back to "a" if it's Ascii value exceeds "z"
char Wrap1 = (char) Ascii1;
char translated = (char)('A' + (Wrap1 -'A') % ('Z' - 'A' + 1));
char Wrap2 = (char) Ascii2;
char translated2 = (char)('A' + (Wrap2 - 'A') % ('Z' - 'A' + 1));
The cleanest way is to use if statements, but this should also work
ch = ( char ) ( ( ch + SHIFT - 'A' ) % 26 + 'A' );
The above only works on uppercase characters and fails on lowercase characters. Here is a solution that works on both upper and lowercase characters, completely free of all if/while/for statements.
public static char shift( char c, int shift ) {
int l = c - 'a';
int u = c - 'A';
// The '>> 31' operator fills all bits with bit 31 of l
int mask = l >> 31;
l = ( l + shift ) % 26;
u = ( u + shift ) % 26;
return ( char ) ( ( ( l + 'a' ) & ~mask ) + ( ( u + 'A' ) & mask ) );
}
The above solution works by calculating the wrapping shift for both lowercase and uppercase characters and masks out the invalid one. mask is -1 if it is a uppercase character or 0 if it is a lowercase character. This is generated by getting the sign bit after subtracting 'a' from the desired character which is negative if it is an uppercase character since 'a' > 'Z'.
I'm trying to implement a basic Caesar Shift Cipher for Java to shift all the letters by 13. Here's my code so far.
public static String cipher(String sentence){
String s = "";
for(int i = 0; i < sentence.length(); i++){
char c = (char)(sentence.charAt(i) + 13);
if (c > 'z')
s += (char)(sentence.charAt(i) - 13);
else
s += (char)(sentence.charAt(i) + 13);
}
return s;
}
However, the program also changes the values of numbers and special characters and I don't want that.
String sentence = "abc123";
returns "nop>?#"
Is there a simple way to avoid the special characters and only focus on letters?
Edit: I should mention I want to keep all the other bits. So "abc123" would return "nop123".
In the following example I encrypt just the letters (more precisely A-Z and a-z) and added the possibility to use any offset:
public static String cipher(String sentence, int offset) {
String s = "";
for(int i = 0; i < sentence.length(); i++) {
char c = (char)(sentence.charAt(i));
if (c >= 'A' && c <= 'Z') {
s += (char)((c - 'A' + offset) % 26 + 'A');
} else if (c >= 'a' && c <= 'z') {
s += (char)((c - 'a' + offset) % 26 + 'a');
} else {
s += c;
}
}
return s;
}
Here some examples:
cipher("abcABCxyzXYZ123", 1) // output: "bcdBCDyzaYZA123"
cipher("abcABCxyzXYZ123", 2) // output: "cdeCDEzabZAB123"
cipher("abcABCxyzXYZ123", 13) // output: "nopNOPklmKLM123"
Note: Due to your code, I assumed that you just want to handle/encrypt the "ordinary" 26 letters. Which means letters like e.g. the german 'ü' (Character.isLetter('ü') will return true) remain unencrypted.
Problem is that you add 13 as a fixed number, and that will for some letters (in second half of alphabet mostly and digits) produce characters that aren't letters.
You could solve this by using array of letters and shifting through those characters. (similar for digits) So something like this
List<Character> chars = ... // list all characters, separate lists for upper/lower case
char c = chars.get((chars.indexOf(sentence.charAt(i)) + 13)%chars.size());
for my project we have to manipulate certain LISP phrasing using Java. One of the tasks is given:
'(A A A A B C C A A D E E E E)
Group the duplicates and make the output like:
′((4A)(1B)(2C)(2A)(1D)(4E))
Notice how the first four A's are kept separate from the last 2...
My issues is with keeping track of how many is each letter. I added the given letters into an array list and I manipulated it a little:
for (int i=0;i<list.size();i++)
{
String val=list.get(i);
String first=list.get(0);
while (val.equals(first))
{
total+=1;
val="X";
}
}
Total should be the number of times of the first occurrence but it keeps giving me 6. 6 is the correct number for all the A's in the sequence, but how do I get it to stop at the first four, record the number and move on the the next letter?
Here is with Java 8 Stream API.
Map<Character, Long> countedDup = Arrays.asList('A' ,'A' ,'A', 'A', 'B', 'C', 'C', 'A', 'A', 'D', 'E', 'E', 'E', 'E')
.stream().collect(Collectors.groupingBy(c -> c, Collectors.counting()));
System.out.println(countedDup);//{A=6, B=1, C=2, D=1, E=4}
This is my solution:
for (int i = 0; i < list.size(); i++) {
String first = list.get(i);
int total = 1;
while (i + 1 < list.size() && first.equals(list.get(i + 1))) {
total++;
i++;
}
System.out.println("(" + total + first + ")");
}
You can debug to know how it run.
***** Note that when compare 2 String objects, never use ==. Use method equals()
This is my solution, though didn't used arrayList:
Edited: as per pointed out by Ascalonian
String text = "'(A A V A B C C X X X X A A Z Z Z K L N N N N N)";
int counter = 1;
System.out.print("'(");
for (int i = 2; i < text.length() - 1; i = i + 2) {
System.out.print("(");
while (((i + 2) < text.length())
&& (text.charAt(i) == text.charAt(i + 2))) {
++counter;
i += 2;
}
System.out.print(counter + "" + text.charAt(i) + ")");
counter = 1;
}
System.out.print(")");
o/p will be for sample text:
((2A)(1V)(1A)(1B)(2C)(4X)(2A)(3Z)(1K)(1L)(5N))
Not sure if using an ArrayList is a requirement, but if not, I use a different approach where I get just the letters, strip away the white spaces, make it a char[] and iterate each letter.
// the initial LISP phrase
String lispPhrase = "'(A A A A B C C A A D E E E E)";
// Pull out just the letters
String letters = lispPhrase.substring(2, lispPhrase.length()-1);
// Remove the white space between them
letters = letters.replaceAll("\\s","");
// Get an array for each letter
char[] letterArray = letters.toCharArray();
char previousLetter = ' ';
char nextLetter = ' ';
int letterCounter = 1;
System.out.print("'(");
// now go through each letter
for (char currentLetter : letterArray) {
// If the first time through, set previousLetter
if (previousLetter == ' ') {
previousLetter = currentLetter;
}else {
nextLetter = currentLetter;
// Is the next letter the same as before?
if (previousLetter == nextLetter) {
letterCounter++;
}else {
// If the next letter is different, print out the previous letter and count
System.out.print("(" + letterCounter + previousLetter + ")");
// Reset the counter back to 1
letterCounter = 1;
}
previousLetter = nextLetter;
}
}
System.out.print("(" + letterCounter + previousLetter + "))");
This gives the output of:
'((4A)(1B)(2C)(2A)(1D)(4E))
In order to get the required output that you specified in your question, I would keep track of the current and next values in the given list. The element count starts at 1 and is incremented when the equality condition is true, otherwise it is reset to 1. And the final output is only updated when the equality condition is false.
Sample code:
EDIT I updated my code based on #Ascalonian's suggestion.
String inputString = "'(A A A A B C C A A D E E E E)";
// I assume that the input always starts with "'("
String finalOutput = inputString.substring(0, 2);
int valCount = 1;
String valCurrent = inputString.substring(2, 3);
String valNext = "";
for (int i = 4; i < inputString.length(); i++) {
valNext = inputString.substring(i, i + 1);
if (valNext.equals(" ")) {
continue;
}
if (valCurrent.equals(valNext)) {
valCount++;
} else {
finalOutput += "(" + valCount + valCurrent + ")";
valCount = 1;
}
valCurrent = valNext;
}
finalOutput += ")";
System.out.println(finalOutput);
Output string: '((4A)(1B)(2C)(2A)(1D)(4E))
I hope this helps.