I have a long String containing literals (both upper and lowercase) and numerals (0 to 9).
I am doing some byte operations on that string. So for example I am replacing all uppercase literals with their lowercase equivalents like this:
byte[] bytes = myString.getBytes();
for (int i = 0; i < bytes.length; i++) {
if(bytes[i] >= 'A' && bytes[i] <= 'Z')
bytes[i] = (byte)( 'a' + (bytes[i] - 'A'));
}
myString = new String(bytes);
I also want to swap all numerals i.e. replace all 0 by 9, all 1 by 8 and so on the same way but couldn't figure out the exact statement. I tried:
if(bytes[i] >= '0' && bytes[i] <= '9') bytes[i] = (byte)( '0' + (bytes[i] - '9'));
but it just adds some special chars to my output, so I think the if statement is wrong. Any idea how to swap those numerals in a byte operation?
Your order of operands is wrong.
bytes[i] = (byte)( '9' - (bytes[i] - '0'));
When doing stuff like this, always have an ascii table at hand http://www.asciitable.com/
In terms of the special chars when manipulating digits, you have the subtraction the wrong way round:
'0' + (bytes[i] - '9')
should be
'0' + ('9' - bytes[i])
If you are manipulating characters, use String.toCharArray(), not String.getBytes(): String is logically a char[], not byte[].
Single characters in the string may be converted to two bytes; doing arithmetic on individual bytes may result in you changing "half" of the character, which will probably lead to funky results when you try to convert it back to a string.
You can do pretty much the same thing using chars instead:
char[] chars = myString.toCharArray();
for (int i = 0; i < chars.length; i++) {
if(chars[i] >= 'A' && chars[i] <= 'Z')
chars[i] = (char) ('a' + (chars[i] - 'A'));
}
myString = new String(chars);
It would be much easier to read and less error-prone to use Character.toLowercase(chars[i]) (similar methods exist for digits), rather than doing arithmetic on character values.
You can't use to replace numbers like the same way you are replacing the lower to upper and vice versa. Because ASCII values for numbers are in series and you are going beyond that limit. Instead of that you have to try 10 if conditions like this;
if(bytes[i] == '0')
bytes[i] = '9'
else if(bytes[i] == '1')
bytes[i] = '8'
And so on....
Related
I came across a code which checks whether a character is between 'a' and 'z' case insensitive. However, I don't understand what the line after that is doing which is:
alphabets[c - 'a']++;
Could someone please explain this code to me?
alphabets = new int[26];
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if ('a' <= c && c <= 'z')
{
alphabets[c - 'a']++; // what does this do?
}
}
This code counts the number of times every lower-case letter appears in the strings. alphabets is an array where the first (i.e., index 0) index holds the number of as, the second the amount of bs, etc.
Subtracting a from the character will produce the relative index, and then ++ will increment the counter for that letter.
A char in Java is just a small integer, 16 bits wide. Generally speaking, the values it holds are the values that Unicode [aside: Java does not represent characters as "ASCII"] assigns to characters, but fundamentally, chars are just integers. Thus 'a' is the integer 0x0061, which can also be written as 97.
So, if you have value in the range 'a' to 'z', you have a value in the range 97 to 122. Subracting 'a' (subtracting 97) puts it in the range 0 to 25, which is suitable for indexing the 26-element array alphabets.
I was looking at the Vigene Ciphere source code provided on http://rosettacode.org/wiki/Vigen%C3%A8re_cipher#Java. I tried testing out the program myself, and it wasn't outputting the values I expect based on vigene. For example 'dog' being the word and 'bob' being the key I would expect this to be encrypted to 'ech', but is 'qot' instead.
public static void main(String[] args) {
String key = "bob";
String ori = "dog";
String enc = encrypt(ori, key);
System.out.println(enc);
}
static String encrypt(String text, final String key) {
String res = "";
text = text.toLowerCase();
for (int i = 0, j = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c < 'a' || c > 'z') continue;
res += (char)((c + key.charAt(j) - 2 * 'A') % 26 + 'A');
j = ++j % key.length();
}
return res;
}
However the output is different. Is this because my understanding of the cipher is incorrect or this has taken a different approach to the well known vigenere cipher.
As what was already pointed out by the user, you should change the line to:
res += (char)((c + key.charAt(j) - 2 * 'a') % 26 + 'a');
Alternatively, you can change this:
if (c < 'a' || c > 'z') continue;
to this:
if (c < 'A' || c > 'Z') continue;
Just ensure when you convert the ASCII back to letters, you are using the correct ASCII value (i.e. 65 (A) for uppercase, 97 (a) for lowercase).
Because you are setting your text to encrypt to lowercase, try changing these character literals to lowercase as well:
res += (char)((c + key.charAt(j) - 2 * 'a') % 26 + 'a');
When casting an int to a char, you have to take into account that the integer value of 'a' is not equal to 'A'. Because you are checking that your current character is between 'a' and 'z' (as you have set it to lowercase), you should also have an output in lowercase as well.
How do I get the numerical value/position of a character in the alphabet (1-26) in constant time (O(1)) without using any built in method or function and without caring about the case of the character?
If your compiler supports binary literals you can use
int value = 0b00011111 & character;
If it does not, you can use 31 instead of 0b00011111 since they are equivalent.
int value = 31 & character;
or if you want to use hex
int value = 0x1F & character;
or in octal
int value = 037 & character;
You can use any way to represent the value 31.
This works because in ASCII, undercase values are prefixed with 011, and uppercase 010 and then the binary equivalent of 1-26.
By using the bitmask of 00011111 and the AND operand, we covert the 3 most significant bits to zeros. This leaves us with 00001 to 11010, 1 to 26.
Adding to the very good (self) answer of Charles Staal.
Assuming ascii encoding following will work. Updated from the kind comment of Yves Daoust
int Get1BasedIndex(char ch) {
return ( ch | ('a' ^ 'A') ) - 'a' + 1;
}
This will make the character uppercase and change the index.
However a more readable solution (O(1)) is:
int Get1BasedIndex(char ch) {
return ('a' <= ch && ch <= 'z') ? ch - 'a' + 1 : ch - 'A' + 1;
}
One more solution that is constant time but requires some extra memory is:
static int cha[256];
static void init() {
int code = -1;
fill_n (&cha[0], &cha[256], code);
code = 1;
for(char s = 'a', l = 'A'; s <= 'z'; ++s, ++l) {
cha[s] = cha[l] = code++;
}
}
int Get1BasedIndex(char ch) {
return cha[ch];
}
We can get their ASCII values and then subtract from the starting character ASCII(a - 97, A - 65)
char ch = 'a';
if(ch >=65 && ch <= 90)//if capital letter
System.out.println((int)ch - 65);
else if(ch >=97 && ch <= 122)//if small letters
System.out.println((int)ch - 97);
Strictly speaking it is not possible to do it portably in C/C++ because there is no guarantee on the ordering of the characters.
This said, with a contiguous sequence, Char - 'a' and Char - 'A' obviously give you the position of a lowercase or uppercase letter, and you could write
Ord= 'a' <= Char && Char <= 'z' ? Char - 'a' :
('A' <= Char && Char <= 'Z' ? Char - 'A' : -1);
If you want to favor efficiency over safety, exploit the binary representation of ASCII codes and use the branchless
#define ToUpper(Char) (Char | 0x20)
Ord= ToUpper(Char) - 'a';
(the output for non-letter character is considered unspecified).
Contrary to the specs, these snippets return the position in range [0, 25], more natural with zero-based indexing languages.
So, what I need to do is translate an array of chars into an array of numbers.
I know this sounds like an odd request, but here's what I've been trying to do:
Have an array like this:
charArray[0] = e;
charArray[1] = b;
charArray[2] = p;
and have it translatated into:
numArray[0] = 5;
numArray[1] = 2;
numArray[2] = 16;
So it would translate the char into it's position in the alphabet (eg. "a" is the 1st letter, "b" is the 2nd, etc)
What's the best way of doing this? I was going to attempt to do it one by one, but then realized I would have way too many lines of code, it would just be tons of nested if statements, and I figured there's probably some better way to do it.
(My way was going to be if charArray[0] = a then numArray[0] = 1, and go through every single letter like that, until you get to if charArray[0] = z then numArray[0] = 26, but that would require 26 different if statements PER CHAR in the char array, which would be a horrible way of doing it in my opinion, because my char array is extremely long.)
You can use a trick For each index i:
numArray[i] = charArray[i] - 'a' + 1;
A more "by the book" way of doing it is:
final String letters = "abcdefghijklmnopqrstuvwxyz";
. . .
numArray[i] = letters.indexOf(charArray[i]) + 1;
Then any positions i such that charAray[i] is not a lower-case letter will end up as 0 in numArray[i]. With the trick, the value of numArray[i] will be something unpredictable.
You can simply:
numArray[i] = charArray[i] - 'a' + 1;
Explanation:
Looking at the ascci table you'll see the decimal value of each char.
a has the decimal value of 97. So you remove 97 from it and add 1. You get 1.
The same for b...z, removing 97 (a) from 98 (b) will be 1, and you add 1 to get 2.. and so on..
Assume all characters are lowercase, you can write:
numArray[0] = (charArray[0] - 'a' + 1);
If you have lowercase and uppercase, you can use an if statement like:
if (charArray[0] >= 'A' && charArray[0] <= 'Z') {
numArray[0] = (charArray[0] - 'A' + 1);
} else {
numArray[0] = (charArray[0] - 'a' + 1);
}
String source = "WEDGEZ"
char letter = source.charAt(i);
shift=5;
for (int i=0;i<source.length();i++){
if (source.charAt(i) >=65 && source.charAt(i) <=90 )
letterMix =(char)(('D' + (letter - 'D' + shift) % 26));
}
Ok what I'm trying to do is take the string WEDGEZ, and shift each letter by 5, so W becomes B and E becomes J, etc. However I feel like there is some inconsistency with the numbers I'm using.
For the if statement, I'm using ASCII values, and for the
letterMix= statement, I'm using the numbers from 1-26 (I think). Well actually, the question is about that too:
What does
(char)(('D' + (letter - 'D' + shift) % 26)); return anyway? It returns a char right, but converted from an int. I found that statement online somewhere I didn't compose it entirely myself so what exactly does that statement return.
The general problem with this code is that for W it returns '/' and for Z it returns _, which I'm guessing means it's using the ASCII values. I really dont know how to approach this.
Edit: New code
for (int i=0;i<source.length();i++)
{
char letter = source.charAt(i);
letterMix=source.charAt(i);
if (source.charAt(i) >=65 && source.charAt(i) <=90 ){
letterMix=(char)('A' + ( ( (letter - 'A') + input ) % 26));
}
}
Well I'm not sure if this homework, so i'll be stingy with the Code.
You're Writing a Caesar Cipher with a shift of 5.
To address your Z -> _ problem...I'm Assuming you want all the letters to be changed into encoded letters (and not weird Symbols). The problem is ASCII values of A-Z lie between 65 and 90.
When coding Z (for eg), you end up adding 5 to it, which gives u the value 95 (_).
What you need to do is Wrap around the available alphabets. First isolate, the relative position of the character in the alphabets (ie A = 0, B = 1 ...) You Need to subtract 65 (which is ASCII of A. Add your Shift and then apply modulus 26. This will cause your value to wrap around.
eg, it your encoding Z, (ASCII=90), so relative position is 25 (= 90 - 65).
now, 25 + 5 = 30, but you need the value to be within 26. so you take modulus 26
so 30 % 26 is 4 which is E.
So here it is
char letter = message(i);
int relativePosition = letter - 'A'; // 0-25
int encode = (relativePosition + shift) % 26
char encodedChar = encode + 'A' // convert it back to ASCII.
So in one line,
char encodedChar = 'A' + ( ( (letter - 'A') + shift ) % 26)
Note, This will work only for upper case, if your planning to use lower case, you'll need some extra processing.
You can use Character.isUpperCase() to check for upper case.
You can try this code for convert ASCII values to Char
class Ascii {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
char ch=sc.next().charAt(0);
if(ch==' ') {
int in=ch;
System.out.println(in);
}
}
}