I'm really loosing my hair over this one. Im making a (simple) encryption program.
Its supposed to take the char make it to an int, add 13 and convert back to a char. Then its supposed to do the same in reverse order. But my only outprint is two blank lines? I know the problem is when I convert back to letters for when I print x everything works. The part I've commented out was something I tried, and while I got an output endtwo was newer like the original text. Also I have to do this in modul 26.
String str = ("helloworld");
String end ="";
String endtwo ="";
for(int i = 0; i < str.length(); i++){
int x = str.charAt(i);
x = ((char)((x+13)%26));
char u =(char)x;
end += u;
//end += ((char)(str.charAt(i)+13));
}
for(int i = 0; i < str.length(); i++){
int x = str.charAt(i);
x = ((char)((x-13)%26));
char u =(char)x;
endtwo += u;
//endtwo += ((char)(str.charAt(i)-13));
}
In Java a char is an integer. Notice that the line
int x = str.charAt(i);
returns an integer which represents the character at the ith location in the String. So what is the value of the integer? You can look up the ASCII table for the letters of the alphabet. You will see that lower case h is 104 in decimal. So you then add 13 to this value so
104 + 13 = 117
You then proceed to mod by 26 which reduces the value to a range 0 to 25.
117 % 26 = 13
Decimal 13 in the ASCII table represents the carriage return character.
Similarly, going the other way you are starting with the 13 and subtracting 13 giving 0 then 0 mod 26 is 0 so 0 is the null character in the ASCII table.
Therefore, rethink your strategy for the encryption algorithm. For example, to get a simple cyclic cipher you can subtract the lower case character 'a' from the character to be encoded.
x = x - 'a';
x = x + 13;
x = x % 26;
x = x + 'a';
This guarantees that you end up with a letter of the alphabet. But only lower case though. How would you modify this to cater for upper case as well?
Also think carefully about the decipher step at the end. Subtracting 13 does not necessarily give you the answer you expect. Hint: Try running the cipher text through the exact same process as the encryption and see what happens.
A very simple approach to implement the ROT13 encryption algorithm is to check in wich range of ASCCI codes is each character, then add 13 or sub 13 depending on the range:
String str = "helloworld";
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c >= 'A' && c < 'N' || c >= 'a' && c < 'n') {
c += 13;
} else if (c >= 'N' && c <= 'Z' || c >= 'n' && c <= 'z') {
c -= 13;
}
}
Related
String input = stack.pop();
if ((index = input.indexOf('*')) != -1) {
for (char c = '0'; c <= '1'; c++) {
input = input.substring(0, index) + c +
input.substring(index + 1);
stack.push(input);
}
}
I'm struggling to understand what's happening in the for loop. Can someone clarify how it iterates? I'm not used to having something other than the length of the array as the second parameter.
When you write for loop like this c have value = 48 accord to ascii table when you increment c it go up to 49 which is equal to 1 also from ascii. So now if you know that you can change your code to this
for (int c = 48; c <= 49; c++)
{
//your code
}
And it is the same. But if you concatenate string like you did value 48 is convert to 0,so * is gonna be replace with 0, in next iteration will be replace with 1.
This is probably a simple fix but I can't seem to solve it.
I am trying to add an integer to the ascii value of characters during a for loop.
It is giving me the error that the program expects a variable rather than a value. How can I do what I am trying to do here?
Here is the code:
public boolean toggleEncryption(){
if(encrypted == false){
for(int i = 0; i < sentence.length(); i++){
if(sentence.charAt(i) >= 65 && sentence.charAt(i) <= 90){
int x = (int)sentence.charAt(i);
x += key;
while(x > 90){
x = x - 26;
}
sentence.charAt(i) += (char)x;
}
}
}
return encrypted;
}
the line sentence.charAt(i) += (char)x; is not working for me
Simple:
sentence.charAt(i) += (char)x;
You wrongly assume that charAt() gives you a "left hand side" thingy. In other words: something that you can assign a value to; like a variable.
But this is not possible: charAt() returns an char value; that represents the char within the string at that index.
It does not give you something that allows you to manipulate the string itself! Strings are immutable; you can't use charAt() to modify its content!
In other words; you can do this:
char c = 'a';
c += 'b';
but you can't use charAt() to achieve the same!
Thus, in order to make your code work, you have to build a new string, like:
StringBuilder builder = new StringBuilder(sentence.length());
for(int i = 0; i < sentence.length(); i++) {
if(sentence.charAt(i) >= 65 && sentence.charAt(i) <= 90){
int x = (int)sentence.charAt(i);
x += key;
while(x > 90){
x = x - 26;
}
builder.append(sentence.charAt(i) + (char)x));
} else {
builder.append(sentence.charAt(i));
}
}
(disclaimer: I just wrote down the above code; there might be typos or little bugs in there; it is meant to be "pseudo code" to get you going!)
Beyond that: I find the name of that method; and how it deals with that boolean field ... a bit confusing. You see, if encryption is true ... the method does nothing?! Then it doesn't "toggle" anything. Thus that name is really misleading resp. not matching what your code is doing!
Here charAt(i) returns a char:
sentence.charAt(i) += (char)x;
1) You cannot assign a character to a value but you can do it to a variable.
2) Even if you used a variable such as
char tempChar = sentence.charAt(i);
You cannot do then :
tempChar += (char)x;
As you cannot increment (+=) a character with another character.
I have to handle some strings, I should put them N positions to left to organize the string.
Here's my code for while:
private String toLeft() {
String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
byte lpad = 2; // Example
StringBuilder sb = new StringBuilder();
for (int i = 0; i < word.length(); i++) {
sb.append((char) (word.charAt(i) - lpad));
}
return sb.toString();
}
It's working for inputs that don't have to move many times...
So, the problem is that when the number N of positions to move is a little bit large (like 10), it returns me non letters, like in the example below, what can I do to prevent it?
Ex.: ABCDEFGHIJKLMNOPQRSTUVWXYZ if I move each char 10 positions to left it returns 789:;<=>?#ABCDEFGHIJKLMNOP while it must return QRSTUVWXYZABCDEFGHIJKLMNOP.
Some inputs and their expected outputs:
VQREQFGT // 2 positions to left == TOPCODER
ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
LIPPSASVPH // 4 positions to left == HELLOWORLD
I think you have misunderstood what your (homework?) requirements are asking you to do. Lets look at your examples:
VQREQFGT // 2 positions to left == TOPCODER
Makes sense. Each character in the output is two characters before the corresponding input. But read on ...
ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
Makes no sense (literally). The letter Q is not 10 characters before A in the alphabet. There is no letter in the alphabet that is before A in the alphabet.
OK so how do you get from A to Q in 10 steps?
Answer ... you wrap around!
A, Z, Y, X, W, V, U, T, S, R, Q ... 10 steps: count them.
So what the requirement is actually asking for is N characters to the left with wrap around. Even if they don't state this clearly, it is the only way that the examples "work".
But you just implemented N characters to the left without wrap around. You need to implement the wrap around. (I won't show you how, but there lots of ways to do it.)
There's another thing. The title of the question says "Decrement only letters" ... which implies to me that your requirement is saying that characters that are not letters should not be decremented. However, in your code you are decrementing every character in the input, whether or not it is a letter. (The fix is simple ... and you should work it out for yourself.)
what can I do to prevent it?
You make it wrap around.
If you want a value to go from 10 to 19 and then start at 10 again, in each iteration you subtract 10, increase by one, take the remainder of that divided by 20, and add 10 again.
Only here, 10 is 'A', 19 is Z, and instead of increasing by one, we add or subtract n.
private String toLeft() {
String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
byte lpad = 10; // Example
StringBuilder sb = new StringBuilder();
int n = -lpad; // I'm using n here to I can use '+ n' below
for (int i = 0; i < word.length(); i++) {
int shifted = word.charAt(i) - 'A' + n;
shifted %= ('Z' - 'A' + 1); // This is for positive n
while(shifted < 0) // And this for negative ones
{
shifted += ('Z' - 'A' + 1);
}
sb.append((char)(shifted + 'A'));
}
return sb.toString();
}
Please read #StephenC's excellent answer about wrap-around. In short, you don't shift left, you rotate left, such that B → A → Z → Y. When you rotate, you wrap around to the other end.
So, for letters you want A-Z to rotate. The easiest rotation method is using modulus (%).
Your logic will be as follows:
Convert letters A-Z into numbers 0-25: n = ch - 'A'
Apply shift and wrap around. Since you're shifting left, you're subtracting from the number, so to prevent negative numbers, you start by shifting a full cycle to the right: n = (n + 26 - shift) % 26
Convert numbers back to letters: ch = (char)(n + 'A')
Here is the code:
private static String rotateLeft(String text, int count) {
char[] buf = text.toCharArray();
for (int i = 0; i < buf.length; i++)
buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
return new String(buf);
}
Of course, you should validate input, and test your code:
private static String rotateLeft(String text, int count) {
char[] buf = text.toCharArray();
if (count <= 0 || count >= 26)
throw new IllegalArgumentException("Invalid count: " + count);
for (char ch : buf)
if (ch < 'A' || ch > 'Z')
throw new IllegalArgumentException("Invalid character: " + ch);
for (int i = 0; i < buf.length; i++)
buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
return new String(buf);
}
public static void main(String[] args) {
System.out.println(rotateLeft("VQREQFGT", 2));
System.out.println(rotateLeft("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10));
System.out.println(rotateLeft("LIPPSASVPH", 4));
}
OUTPUT
TOPCODER
QRSTUVWXYZABCDEFGHIJKLMNOP
HELLOWORLD
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());
I've reading this question, and I was wondering if Is there any way to consider the whole range of characters? For example, "á", "é", "ö", "ñ", and not consider " " (the [Space])? (For example, my String is "Hello World", and the standard result is "Khoor#Zruog"; I want to erase that "#", so the result would be "KhoorZruog")
I'm sure my answer is in this piece of code:
if (c >= 32 && c <= 127)
{
// Change base to make life easier, and use an
// int explicitly to avoid worrying... cast later
int x = c - 32;
x = (x + shift) % 96;
chars[i] = (char) (x + 32);
}
But I've tried some things, and it didn't work.
See this pseudocode - should be trivially implementable:
// you need to define your own range, obviously - it's not at all obvious whether
// e.g. "ź" should be included and that it should come after "z"
array char_range = ['a','á','b','c','č', (...), 'z','ź','ž']
// the text to encode
string plaintext = 'some text here'
// this will contain encoded text
stringbuilder ciphertext = ''
// the classic Caesar Cipher shifts by 3 chars to the right
// to decipher, reverse the sign
int shift_by = 3
// note: character != byte, esp. not in UTF-8 (1 char could be 1 or more bytes)
for each character in plaintext
get character_position of character in char_range // e.g. "a" would return 0
if not in char_range // e.g. spaces and other non-letters
do nothing // drop character
// alternately, you can append it to ciphertext unmodified
continue with next character
add shift_by to character_position
if character_position > char_range.length
character_position modulo char_range.length
if character_position < 0 // useful for decoding
add char_range.length to character_position
get new_character at character_position
append new_character to ciphertext
done
The Space as the ASCII Code 32 which you don't filter out. You could try:
if (c >= 33 && c <= 127)
{
// Change base to make life easier, and use an
// int explicitly to avoid worrying... cast later
int x = c - 32;
x = (x + shift) % 96;
chars[i] = (char) (x + 32);
}
I just changed the 32 with a 33 in your if-Clause so that the spaces are simply ignored.
You could use this. It will check for you it the given int value represents a literal.
Character
So your function could look like this:
if (Character.isLiteral(c) )
{
// Change base to make life easier, and use an
// int explicitly to avoid worrying... cast later
int x = c - Character.MIN_VALUE;
x = (x + shift) % Character.MAX_VALUE;
chars[i] = (char) (x + Character.MIN_VALUE);
}