3

For my assignment, I have to write a code to encode/decode a message. I am near the end when I began to discover that whenever I type the message, the program only replaces certain characters. The translation is fairly simple, to encode, you change a to the opposite letter of the alphabet, so z. b to y, c to x, d to w, etc. The Assignment is as follows:

This project involves writing a program that encodes and decodes messages. The program should prompt the user to select whether a message is to be encoded or decoded and then prompts the user to enter the message. A blank space is used to separate each word in the message, and a period (.) is used to denote the end of a sentence. Separate methods must be used to encode and decode the input message. The coding scheme is very simple: the code equivalent for the letter A is Z, for B is Y, … , and for Z is A, as indicated in the following table. As an example, if the user chooses to encode a sentence like hello world, the encoded sentence would be svool dliow.

Here is my code:

import java.util.Scanner ; public class Project1 { public static void main(String[] args) { Scanner input = new Scanner(System.in) ; //prompt user to decide to encode or decode System.out.print("Please enter 1 to encode, or 2 to decode the message: ") ; int promptNumber = input.nextInt() ; if (promptNumber == 1) { System.out.println("You have choosen to encode the message.") ; System.out.print("Please enter the message you wish to be encoded: ") ; String encode = input.next(); encode += input.nextLine(); encode = encodeMessage(encode) ; System.out.println("Your encoded message is now: " + encode) ; } else if (promptNumber == 2) { System.out.println("You have choosen to decode the message.") ; System.out.print("Please enter the message you wish to decode: ") ; String decode = input.next(); decode += input.nextLine(); decode = decodeMessage(decode) ; System.out.println("Your encoded message is now: " + decode) ; } else System.out.println("Please enter a value of 1 or 2.") ; } //method for encoded calculation public static String encodeMessage(String message) { String str = message ; for (int i = 0; i < str.length(); i++) { switch (str.charAt(i)) { case 'a': str = str.replace('a', 'z') ; break ; case 'b': str = str.replace('b', 'y') ; break ; case 'c': str = str.replace('c', 'x') ; break ; case 'd': str = str.replace('d', 'w') ; break ; case 'e': str = str.replace('e', 'v') ; break ; case 'f': str = str.replace('f', 'u') ; break ; case 'g': str = str.replace('g', 't') ; break ; case 'h': str = str.replace('h', 's') ; break ; case 'i': str = str.replace('i', 'r') ; break ; case 'j': str = str.replace('j', 'q') ; break ; case 'k': str = str.replace('k', 'p') ; break ; case 'l': str = str.replace('l', 'o') ; break ; case 'm': str = str.replace('m', 'n') ; break ; case 'n': str = str.replace('n', 'm') ; break ; case 'o': str = str.replace('o', 'l') ; break ; case 'p': str = str.replace('p', 'k') ; break ; case 'q': str = str.replace('q', 'j') ; break ; case 'r': str = str.replace('r', 'i') ; break ; case 's': str = str.replace('s', 'h') ; break ; case 't': str = str.replace('t', 'g') ; break ; case 'u': str = str.replace('u', 'f') ; break ; case 'v': str = str.replace('v', 'e') ; break ; case 'w': str = str.replace('w', 'd') ; break ; case 'x': str = str.replace('x', 'c') ; break ; case 'y': str = str.replace('y', 'b') ; break ; case 'z': str = str.replace('z', 'a') ; break ; case ' ': continue ; case '.': break ; } } return str ; } //method for decoded calculation public static String decodeMessage(String message) { String str = message ; for (int i = 0; i < str.length(); i++) { switch (str.charAt(i)) { case 'a': str = str.replace('a', 'z') ; break ; case 'b': str = str.replace('b', 'y') ; break ; //Error case 'c': str = str.replace('c', 'x') ; break ; case 'd': str = str.replace('d', 'w') ; break ; //Error case 'e': str = str.replace('e', 'v') ; break ; case 'f': str = str.replace('f', 'u') ; break ; case 'g': str = str.replace('g', 't') ; break ; case 'h': str = str.replace('h', 's') ; break ; case 'i': str = str.replace('i', 'r') ; break ; case 'j': str = str.replace('j', 'q') ; break ; case 'k': str = str.replace('k', 'p') ; break ; case 'l': str = str.replace('l', 'o') ; break ; //Error case 'm': str = str.replace('m', 'n') ; break ; case 'n': str = str.replace('n', 'm') ; break ; case 'o': str = str.replace('o', 'l') ; break ; case 'p': str = str.replace('p', 'k') ; break ; case 'q': str = str.replace('q', 'j') ; break ; case 'r': str = str.replace('r', 'i') ; break ; case 's': str = str.replace('s', 'h') ; break ; case 't': str = str.replace('t', 'g') ; break ; case 'u': str = str.replace('u', 'f') ; break ; case 'v': str = str.replace('v', 'e') ; break ; case 'w': str = str.replace('w', 'd') ; break ; case 'x': str = str.replace('x', 'c') ; break ; case 'y': str = str.replace('y', 'b') ; break ; //Error case 'z': str = str.replace('z', 'a') ; break ; case ' ': continue ; case '.': break ; } } return str ; } } 
2
  • Your program does not take into consideration uppercase alphabets. Commented Jul 10, 2020 at 18:33
  • 1
    Have you tried debugging your code? Commented Jul 10, 2020 at 18:40

6 Answers 6

2

It seems that you're iterating over your string by index, and instead of changing the current index, you're changing all occurrences of that particular value in that string, regardless if you have changed it, or still need to change it.

Let's clarify this with an example: "aba" with the following cypher: a => b, b => a

index 0: a => change all occurrences of a => result: bbb index 1: b => change all occurrences of b => result: aaa index 2: a => change all occurrences of a => result: bbb 

while you clearly expected to shift every index only once. If we change this in your current code, using lets say an char[] to change the value in the current index, we get something like this:

public static String encodeMessage(String message) { char[] str = message.toCharArray(); for (int i = 0; i < str.length; i++) { switch (str[i]) { case 'a': str[i] = 'z'; break; case 'b': str[i] = 'y'; break; case 'c': str[i] ='x'; break; case 'd': str[i] ='w'; break; case 'e': str[i] = 'v'; break; case 'f': str[i] = 'u'; break; case 'g': str[i] = 't'; break; case 'h': str[i] = 's'; break; case 'i': str[i] = 'r'; break; case 'j': str[i] = 'q'; break; case 'k': str[i] = 'p'; break; case 'l': str[i] = 'o'; break; case 'm': str[i] = 'n'; break; case 'n': str[i] = 'm'; break; case 'o': str[i] = 'l'; break; case 'p': str[i] = 'k'; break; case 'q': str[i] = 'g'; break; case 'r': str[i] = 'i'; break; case 's': str[i] = 'h'; break; case 't': str[i] = 'g'; break; case 'u': str[i] = 'f'; break; case 'v': str[i] = 'e'; break; case 'w': str[i] = 'd'; break; case 'x': str[i] = 'c'; break; case 'y': str[i] = 'b'; break; case 'z': str[i] = 'a'; break; case ' ': continue; case '.': break; } } return new String(str); } 

et voila:

Your encoded message is now: svool dliow

Sign up to request clarification or add additional context in comments.

Comments

1

Your decode and encode methods are logically exactly the same so you don't need to create separate methods for them.

You can use Java 8 Streams for a more functional and readable code. Here I worked with the ASCII values of each character and obtained the corresponding encoded (or decoded depending upon how you look at it) value.

public static String encodeOrDecode(String s) { return s.chars() // create int stream .map(i -> Character.isAlphabetic(i) ? (Character.isUpperCase(i) ? 155 - i: 219 - i) : i) // encode / decode .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) // convert intstream to StringBuilder .toString(); // StringBuilder to String } 

Comments

1

I suggest you use the basic arithmetic to avoid so long switch-case which not only looks ugly but is also difficult to debug in case of any problem. The ASCII value of A is 65 and that of Z is 90. For lowercase alphabets, it starts from 97 and ends at 122. You can use these values to define a formula for encoding and decoding as shown below:

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter a sentence: "); String message = scanner.nextLine(); System.out.println("Encoded: " + encodeOrDecodeMessage(message)); System.out.println("Decoded: " + encodeOrDecodeMessage(encodeOrDecodeMessage(message))); } public static String encodeOrDecodeMessage(String message) { StringBuilder sb = new StringBuilder(); for (char ch: message.toCharArray()) { if (Character.isAlphabetic(ch)) { sb.append(Character.isUpperCase(ch) ? (char) (90 + 65 - ch) : (char) (122 + 97 - ch)); } else { sb.append(ch); } } return sb.toString(); } } 

A sample run:

Enter a sentence: hello world Encoded: svool dliow Decoded: hello world 

Another sample run:

Enter a sentence: Hello World! Encoded: Svool Dliow! Decoded: Hello World! 

Comments

0

I'll give you a few pointers so that you can work on that to fix the issue. You have used the String replace method. What it does is, it would replace all occurrences of a particular word with the substitute character specified. Let's say String sample = "aaaaaa"; When you call sample.replace('a','z');, the whole string will be converted to zzzzzzz. This is one of the reasons your code is not working properly. If you want to replace only the first occurence, you might want to check String replaceFirst method

In your multiple switch cases, when you are substituting one character for others, you are substituting with g for two characters (q and t) which would cause a logical bug.

When you are getting input from the user, you initially get once using next() and again using nextLine(). Instead of doing it like that twice, You can just use nextLine() to get a whole sentence. By default, nextLine() uses new line as the delimiter, that is the end of the line. If you want to use "." as the end of the line, you can use it as input.nextLine("."). This way, you will be able to read each line till full stop, remove next() which uses " " as a delimiter and also remove the case for "." in your switch statement.

When you pass some value to a function as you have done in:

public static String decodeMessage(String message) { //Code } and public static String encodeMessage(String message) { //Code } 

you can directly use the message inside the function. There is no need to assign it again to some other variable str.

Lastly, what you are trying to implement is called a Caesar Cipher. Instead of having many switch cases and implementing it, you can do the same in a much better way. If you refer to the Wikipedia article that I have linked, you can see how the same can be done using modular arithmetic. If you are not sure about how you can proceed, look into ASCII. Long story short, using modular arithmetic and ASCII values, the same can be done using few lines. So I would suggest you to look into it.

Comments

0

interesting question. Seeing how everyone else has already revealed the issue to be that you are replacing characters after encoding them, I won't bother explaining it. When I was taking Object Oriented Programming I, they did not allow us to use anything like ArrayList. That being said, here is a solution that doesn't require any imports.

//method for encoded calculation public static String encodeMessage(String message) { String encoded = message.toUpperCase(); for (int i = 0; i < message.length(); i++) { int c = encoded.charAt(i); if (65 <= c && c <= 77) { // first half of the alphabet int numC = 90 - (c - 65); char newC = (char) numC; encoded = encoded.substring(0, i) + newC + encoded.substring(i + 1); } if (77 < c && c <= 90) { // second half of the alphabet int numC = 65 + (90 - c); char newC = (char) numC; encoded = encoded.substring(0, i) + newC + encoded.substring(i + 1); } } return encoded.toLowerCase(); } 

As opposed to having a switch case for every single letter of the alphabet, I wrote an equation that uses the unicode values of the characters (calling .toUpperCase() in order to make the string uniform). Take for example the character C (unicode value of 67). The equation is as follows: 90 - (char - 65) for the first half of the alphabet and 65 + (90 - char) for the second half. C is in the first half of the alphabet therefore the equation would result in 90 - ( 67 - 65) = 88, the unicode value for "X". This is useful for encoding the letters but it applies both ways. Say you were to call encodeMessage("hello"); the output would be svool, encoding it again would simply decode the message back to the original. This means that your decodeMessage method is one simple line where you call encodeMessage.

 // method for decoded calculation public static String decodeMessage(String message) { return encodeMessage(message); } 

If you would like to learn more about unicode, there is a convenient table on this page. Also, I recommend reading the documentation for the substring method in the String class here. I hope this helps, send me a message if you have questions, as my reputation is not high enough to respond to comments.

Comments

0

In the alphabet we have 26 letters, from a to z. In java if we convert a character to an int, we get a number, from 97 to 122.

enter image description here

String str = "abc zyx"; char[] ch = str.toCharArray(); int a = 97; int z = 122; LOOP:for (int i =0; i< ch.length; i++) { int no = ch[i]; // if we don't find an alphabetic character, continue iteration if ((no < 97) || (no > 122)) continue LOOP; // if character is less than half of the alphabet // we switch the characters if (no <= 109) { int findDif = z - no; int findLetter = a + findDif; char replacedLetter = (char)findLetter; ch[i] = replacedLetter; continue LOOP; } // and the other side if (no >= 110) { int findDif = z - no; int findLetter = a + findDif; char replacedLetter = (char)findLetter; ch[i] = replacedLetter; continue LOOP; } } String converted = new String(ch); System.out.println(converted); // [z,y,x, , a,b,c] 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.