Reputation: 1080
I tried to implement Rot13 and to make it as minimal as possible, this are my results so far:
if ( (c >= 'A') && (c <= 'Z') )
c=((c-'A'+13)%26)+'A';
if ( (c >= 'a') && (c <= 'z') )
c=((c-'a'+13)%26)+'a';
return c;
I showed this to my Prof and he said it would be possible in two lines. I don't know how i could shrink this code further and not generating wrong output.
Thanks for your help
EDIT: if nothing changed (outer range ascii) it should only return c. Maybe the solution is the second answer + return line c in case nothing returned.
Upvotes: 1
Views: 619
Reputation: 154
Even shorter and (perhaps) still easier to read is
char a = c < 'a' ? 'A' : 'a';
return (c - a + 13) % 26 + a;
Note that this solution, like some of the previous answers, doesn't check the input. Moreover, in Java this code returns an int, not a char, so a cast would be necessary if the method in which it is included returns a char.
As already mentioned, I also like to stress that shortest is not necessarily best. Write readable code.
Upvotes: 1
Reputation: 181077
Well, if we're going for short over readable;
return (c&~32) >= 'A' && (c&~32) <= 'Z' ? ((c&31) + 12) % 26 + (c&~31) + 1 : c;
Upvotes: 0
Reputation: 68907
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
Upvotes: 3
Reputation: 13717
Slightly more correct than Sibbo's answer. This returns c as is if it falls in neither range. and in 1 line.
return ((c >= 'A') && (c <= 'Z')) ? ((c-'A'+13)%26)+'A'
:((c >= 'a') && (c <= 'z') ? ((c-'a'+13)%26)+'a'
: c);
Upvotes: 2
Reputation: 3914
One line:
return (c < 'a') ? ((c - 'A' + 13) % 26) + 'A' : ((c - 'a' + 13) % 26) + 'a';
This simply makes use of the fact that lower case letters come after upper case letters in ASCII and UTF-8. Of course, it doesn't verify the input in any way.
Upvotes: 3
Reputation: 59343
You don't need to update c
; just return:
if ((c >= 'A') && (c <= 'Z')) {
return ((c - 'A' + 13) % 26) + 'A';
}
if ((c >= 'a') && (c <= 'z')) {
return ((c - 'a' + 13) % 26) + 'a';
}
I also made the code more readable.
This could easily be made into two lines:
if ((c >= 'A') && (c <= 'Z')) return ((c - 'A' + 13) % 26) + 'A';
if ((c >= 'a') && (c <= 'z')) return ((c - 'a' + 13) % 26) + 'a';
Or one:
if ((c >= 'A') && (c <= 'Z')) return ((c - 'A' + 13) % 26) + 'A'; if ((c >= 'a') && (c <= 'z')) return ((c - 'a' + 13) % 26) + 'a';
But of course, that is much less readable, and not a good idea.
Upvotes: 3