Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

66%
+2 −0
Q&A How can the Caesar cipher be implemented in Java?

Caesar Cipher originally deals only with letters (ASCII "A" to "Z", without diacritics/accents), so I'm not sure why you included ۤ$%& in your answer. And using indexOf (as you did) is not ver...

posted 2y ago by hkotsubo‭

Answer
#1: Initial revision by user avatar hkotsubo‭ · 2022-03-09T12:51:47Z (over 2 years ago)
Caesar Cipher originally deals only with letters (ASCII "A" to "Z", without diacritics/accents), so I'm not sure why you included `ۤ$%&` in [your answer](https://software.codidact.com/posts/286080/286081#answer-286081). And using `indexOf` (as you did) is not very efficient, because it always makes a *loop* through the string, until the character is found (which means you're looping the alphabet string lots of times, [which might not be a good idea](https://www.joelonsoftware.com/2001/12/11/back-to-basics/)).

Of course for small strings this won't make much difference, but anyway, to implement this cipher (shifting only ASCII letters) you don't need a string with the whole alphabet. Just use the char's ASCII code and do some calculations with it. To eliminate the problem of the `%` operator with negative numbers, use [`Math.floorMod`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Math.html#floorMod(int,int)), which guarantees that the result is positive (**actually**, `Math.floorMod(x, y)` guarantees that the result has the same sign of `y`, and we're going to use `y` equals 26, so this will do the trick)[^1]:

  [^1]: Of course you could also use your `mod` function, I'm just showing a native "*batteries included*" solution.

```java
public static String caesarCipher(String s, int shift) {
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        char base;
        // check if it's an ASCII letter
        if ('A' <= c && c <= 'Z') {
            base = 'A';
        } else if ('a' <= c && c <= 'z') {
            base = 'a';
        } else {
            // not a letter, char remains the same in the new string
            result.append(c);
            continue; // go to next char
        }
        // it only gets here if it's an ASCII letter
        result.append((char) (Math.floorMod((c - base) + shift, 26) + base));
    }
    return result.toString();
}
```

First I check if the character to be shifted is a lowercase or uppercase ASCII letter, and set the base letter accordingly (for non-letters, I'll just add them to the result without any modification, but you can also throw an exception if those are not to be accepted). Then I "normalize" the character relative to the base letter (so "A"/"a" becomes zero, "B"/"b" becomes 1 and so on). Then I add the shift and get the `floorMod` of that by 26.

After that, I'll just add the base again, so 0 becomes "A" (or "a", if the base is lowercase), 1 becomes "B"/"b", etc.

Testing:

```java
String s = "aA bB yY zZ 123";
String ciphered = caesarCipher(s, 3);
System.out.println(ciphered);
String deciphered = caesarCipher(ciphered, -3);
System.out.println(deciphered);
```

Output:

```none
dD eE bB cC 123
aA bB yY zZ 123
```

As I said, I'm ignoring (keeping unchanged) all the characters that aren't letters, but you can also throw an exception if those are not allowed in the input string. The [description in Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher) doesn't say what to do with non-letters, but in the examples we can see that at least spaces are allowed (and kept unchanged). You could include those specific checks if you want, but I guess that's beside the point <sup><sub>and left as an exercise for the reader</sub></sup>.

---
# "Generic" alphabet

If you want a more generic alphabet (as you did in your answer, by including `ۤ$%&`), the calculations won't work anymore, and the `indexOf` approach could be used instead.

But if this will be used in lots of strings, `indexOf` won't be very efficient (as already said above), and perhaps it'd be worth to do some pre-processing in the alphabet:

```java
public class CaesarCipher {
    private int encriptionShift;
    private String alphabet;
    private Map<Character, Integer> positions; // map each char to its position in the alphabet

    // receives the alphabet and the shift for encription
    public CaesarCipher(String alphabet, int encriptionShift) {
        this.encriptionShift = encriptionShift;
        this.alphabet = alphabet;
        this.positions = new HashMap<>(alphabet.length());
        for (int i = 0; i < alphabet.length(); i++) {
            this.positions.put(alphabet.charAt(i), i);
        }
    }

    private String shiftString(String s, int shift) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (this.positions.containsKey(c)) {
                int pos = this.positions.get(c);
                int newPosition = Math.floorMod(pos + shift, this.alphabet.length());
                result.append(this.alphabet.charAt(newPosition));
            } else {
                // char not in the alphabet, keeping unchanged
                // (or throw exception if you don't want to allow those)
                result.append(c);
            }
        }
        return result.toString();
    }

    public String cipher(String s) {
        return this.shiftString(s, this.encriptionShift);
    }

    public String decipher(String s) {
        return this.shiftString(s, -this.encriptionShift);
    }
}
```

Now each character is mapped to its position in the alphabet (only once, when the instance is created), and I use this map instead of `indexOf` (it's a classic trade-off: the map uses extra memory, but I avoid all the loops caused by `indexOf`). Of course you need to analyze if performance is an issue and if it's worth doing it, but anyway...

Testing:

```java
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzۤ$%&";
CaesarCipher c = new CaesarCipher(alphabet, 3);

String plaintext = "ۤ$%&0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String ciphertext = c.cipher(plaintext);
String decrypted = c.decipher(ciphertext);
System.out.println(plaintext);
System.out.println(ciphertext);
System.out.println(decrypted);
```

Output:

```none
ۤ$%&0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
%&ABC3456789abcdefghijklmnopqrstuvwxyzۤ$DEFGHIJKLMNOPQRSTUVWXYZ012
ۤ$%&0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
```