6

Please can someone explain the line of code highlighted below. I don't understand at all how this line works.

You can use this example to help me:

input:   ATTACK  
keyword: LEMON  
res:     LXFOPV

I don't understand how that line helps encode A to L and other letter... ACSII involvement?

static String encrypt(String text, final String key) {
    String res = "";
    text = text.toUpperCase();
    for (int i = 0, j = 0; i < text.length(); i++) {
        char c = text.charAt(i);
        if (c < 'A' || c > 'Z') continue;
 ////////////////////////////////////////////////////////////////////////////
//please someone explain this line
        res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A'); 
////////////////////////////////////////////////////////////////////////

        j = ++j % key.length();
    }
    return res;
}
Duncan Jones
  • 59,308
  • 24
  • 169
  • 227
JavaBeginner
  • 105
  • 5

1 Answers1

6

Background

The code uses the ASCII value of the letters. The letters A-Z are ASCII values 65-90.

The idea is to add the two letters together, but wrap around if the values goes above 90 (known as modular arithmetic). So 91 should actually be 65 (i.e. Z + 1 = A).

Java provides a % operator for doing modular arithmetic (x % n). However, this is designed to work on a range of numbers 0→n-1. So, if we subtract 65 from each of our letters, we are then working in the range 0→25. This allows us to use the modulus operator (x % 26).

This is what the code is doing:

c + key.charAt(j) - 2 * 'A'

This part adds the two letters together, but also subtracts 65 from each of them. It may be easier to understand if written as:

(c - 'A') + (key.charAt(j) - 'A')

You'll notice that you can do - 'A' as a convenient way of doing - 65.

Now we have a value that's zero-based, but possibly larger than 25. So we then modulo it:

(c + key.charAt(j) - 2 * 'A') % 26

We then need to add 65 back to the value, to bring it back into the A-Z range for ASCII:

(c + key.charAt(j) - 2 * 'A') % 26 + 'A'

The only remaining step is to cast this to a char, since the result is an int by default:

res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A'); 

Example

If the input is ATTACK and the keyword is LEMON, then at some point we are going to have to consider the input letter T (ASCII 84) and the key letter M (ASCII 77).

Subtracting 65 from each, we have T=19 and M=12. Added together, we get 31.

31 % 26 = 5. So we then calculate 5+65=70, which is the ASCII value for F.

Community
  • 1
  • 1
Duncan Jones
  • 59,308
  • 24
  • 169
  • 227
  • 1
    Nice explanation, but Java's `char` holds a Unicode/UTF-16 code unit, not an ASCII codepoint. Yes, for the characters in question, all the values are the same but thinking the range of `char` is 0-127 or that any 16-bit value is a valid UTF-16 code unit could lead to bugs. Arithmetic can work over only certain ranges of `char` values. – Tom Blodget Feb 27 '15 at 02:48
  • @TomBlodget Yes, good point. It doesn't affect this code, but it is helpful if the OP doesn't misunderstand what a `char` can hold. – Duncan Jones Feb 27 '15 at 08:23