There is a little trick using the ASCII table. Upper and lower case chars only differ one bit. So you could handle them at once. Take a look at this:
A = 0100 0001 M = 0100 1101
a = 0110 0001 m = 0110 1101
So, I think this should work:
if (Character.isLetter(c))
return (char) ((((c & 0b01011111) - 'A' + 13) % 26 + 'A') | (c & 0b00100000));
return c;
Explanation:
c & 0b01011111
turns the char into an uppercase.
- 'A' + 13
converts to an 0-based int and applies the offset.
% 26 + 'A'
Take the modulo and make it back a char.
(c & 0b00100000)
takes the bit that indicates wether the char was lower case or not.
|
Add that bit back to the result to make it lowercase if it was.
You could use the conditional operator here to make it a one-liner:
return Character.isLetter(c) ? (char) ((((c & 0b01011111) - 'A' + 13) % 26 + 'A') | (c & 0b00100000)) : c;
After replacing the binary and char literals by decimal int literals, you get:
return Character.isLetter(c) ? (char) ((((c & 95) - 52) % 26 + 65) | (c & 32)) : c;
Eliminating spaces and some extra brackets gives: (65 chars)
return Character.isLetter(c)?(char)((((c&95)-52)%26+65)|c&32):c;
Which is a win, IMHO, if it comes to code golfing. This is of course not readable.
Demo: Yep, confirmed. It works: http://ideone.com/l6xYy6
Excerpt from the output:
= -> =
> -> >
? -> ?
@ -> @
A -> N
B -> O
C -> P
D -> Q
And a bit further:
W -> J
X -> K
Y -> L
Z -> M
[ -> [
\ -> \
] -> ]
^ -> ^
_ -> _
` -> `
a -> n
b -> o
c -> p
d -> q