I have implemented the Caesar Cipher algorithm in Java 8.
The Problem
Heute ist Freitag.
results into this encoded text using 22 as a key:
^{
{6
6{
w}D
Decoding this again gets me this output:
Heu
e is
Frei
ag.
The Code and description
It should be noted that my algorithm doesn't care about characters like '\n', meaning some characters might be translated to escape sequences or spaces etc.
This is also totally what I want to happen, thought it doesn't work.
public String encode(String txt, int key) {
if(key <= 0)
return txt;
String result = "";
for (int i = 0; i < txt.length(); i++) {
int x = (txt.charAt(i) + key) % 128;
result += (char) x;
}
System.out.println(result);
return result;
}
public String decipherM(String txt, int key) {
if(key <= 0)
return txt;
String result = "";
for (int i = 0; i < txt.length(); i++) {
int x = (txt.charAt(i) - key) % 128;
if(x < 0)
x += 128;
result += (char) x;
}
System.out.println(result);
return result;
}
The question
I would really like to know why it doesn't work with escape sequences or other non alphabetic characters.
Control characters have a defined meaning and text processing tools may retain the meaning or even remove those control characters not having a valid meaning, rather than retaining the exact byte representation.
Note that when you go beyond ASCII, this may even happen with ordinary characters, e.g. since you used a German sample text, you have to be aware that the two Unicode codepoint sequences \u00E4 and \u0061\u0308 are semantically equivalent, both referring to the character ä and you can not rely on text processing tool to retain both forms.
After all, there is a reason why encodings like Base 64 have been invented for lossless transfer of byte sequences through text processing tools.
For an encoding as simple as yours, it might be the best to simply forbid control characters in the source string and rotate only through the ASCII non-control character range:
public String encodeRotation(String txt, int distance) {
int first = ' ', last = 128, range = last - first;
while(distance<0) distance+=range;
if(distance == 0) return txt;
char[] buffer = txt.toCharArray();
for (int i = 0; i < txt.length(); i++) {
char c = buffer[i];
if(c<first || c>=last)
throw new IllegalArgumentException("unsupported character "+c);
buffer[i] = (char) ((c - first + distance) % range + first);
}
return String.valueOf(buffer);
}
public String decodeRotation(String txt, int key) {
return encodeRotation(txt, -key);
}
System.out.println(encodeRotation("Heute ist Freitag.", 22));
^{+*{6)*6\({*w}D
System.out.println(decodeRotation("^{+*{6)*6\\({*w}D", 22));
Heute ist Freitag.
Related
i need to reverse the following algorithm which converts a long array into a string:
public final class LongConverter {
private final long[] l;
public LongConverter(long[] paramArrayOfLong) {
this.l = paramArrayOfLong;
}
private void convertLong(long paramLong, byte[] paramArrayOfByte, int paramInt) {
int i = Math.min(paramArrayOfByte.length, paramInt + 8);
while (paramInt < i) {
paramArrayOfByte[paramInt] = ((byte) (int) paramLong);
paramLong >>= 8;
paramInt++;
}
}
public final String toString() {
int i = this.l.length;
byte[] arrayOfByte = new byte[8 * (i - 1)];
long l1 = this.l[0];
Random localRandom = new Random(l1);
for (int j = 1; j < i; j++) {
long l2 = localRandom.nextLong();
convertLong(this.l[j] ^ l2, arrayOfByte, 8 * (j - 1));
}
String str;
try {
str = new String(arrayOfByte, "UTF8");
} catch (UnsupportedEncodingException localUnsupportedEncodingException) {
throw new AssertionError(localUnsupportedEncodingException);
}
int k = str.indexOf(0);
if (-1 == k) {
return str;
}
return str.substring(0, k);
}
So when I do the following call
System.out.println(new LongConverter(new long[]{-6567892116040843544L, 3433539276790523832L}).toString());
it prints 400 as result.
It would be great if anyone could say what algorithm this is or how i could reverse it.
Thanks for your help
This is not a solvable problem as stated because
you only use l[0] so any additional long values could be anything.
it is guaranteed that there is N << 16 solutions to this problem. While the seed for random is 64-bit in reality the value used internally is 48-bit. This means is there is any solution, there if at least 16K solutions for a long seed.
What you can do is;
find the smallest seed which would generate the string using brute force. For a short strings this won't take long, however if you have 5-6 character this will take a while and for 7+ character there might not be a solution.
instead of generating 8-bit characters where all 8-bit values are equal. You could restrict the range to say space, A-Z, a-z and 0-9. This means you can have ~6-bits of randomness, shorter seeds and slightly longer Strings.
BTW You might find this post interesting where I use contrived random seeds to generate specific sequences. http://vanillajava.blogspot.co.uk/2011/10/randomly-no-so-random.html
If you want a process which ensures you can always re-create the original longs from a String or a byte[], I suggest using encryption. You can encrypt a String which has been UTF-8 encoded or a byte[] into another byte[] which can be base64 encoded to be readable as text. (Or you could skip the encryption and use base64 alone)
I'm not to sure how to use character math. In my program, i have a character array and i have to change the elements of the array, so that its the opposite of the character entered by the user. Example 'a' to 'z'. i guess i can change each element in the array, but that would take forever and would be a waste of time. So far i have tried nothing, i just don't know where to start.
import java.util.*;
public class SecretCodeMachine
{
public static void main(String[]args)
{
SecretCodeMachine a = new SecretCodeMachine();
Scanner in = new Scanner (System.in);
String input = in.nextLine();
String print = a.encodeMessage(input);
System.out.println(print);
}
public String encodeMessage(String pass)
{
char[] j = pass.toCharArray();
String b = new String(j);
return b;
}
}
I have written the encodingMessage() method where all that code would be, im just not sure how i would approach this. Would i most likely use some type of loop?
The simplest solution would be to create a lookup table of valid input characters and what the output character should be. This can be done with either a map or array, that is up to you. Then for each character, you would look it up in the table and place the output character into the new string.
But if you really need to use character math, which I can only assume meaning, converting the character to its corresponding ASCII int value, then doing some math to result in the correct int value of the resulting character. This will be much more complex, but it can be done.
You can condition on whether it is in the first half of the alphabet or the second half, and do arithmetic with characters directly.
import java.util.*;
public class SecretCodeMachine
{
public static void main(String[]args)
{
SecretCodeMachine a = new SecretCodeMachine();
Scanner in = new Scanner (System.in);
String input = in.nextLine();
String print = a.encodeMessage(input);
System.out.println(print);
}
public String encodeMessage(String pass)
{
char[] j = pass.toCharArray();
for (int i = 0; i < j.length; i++) {
// Lower case
if (j[i] >= 'a' && j[i] <= 'z') {
if (j[i] - 'a' <= 13) j[i] = (char) ('z' - (j[i] - 'a'));
else j[i] = (char) ('a' + ('z' - j[i]));
}
// Upper Case
else {
if (j[i] - 'A' <= 13) j[i] = (char) ('Z' - (j[i] - 'A'));
else j[i] = (char) ('A' + ('Z' - j[i]));
}
}
String b = new String(j);
return b;
}
}
this will work for all lowercase and here is a link to the ASCII Table for your reference
for(int i = 0; i < j.length ; i ++){
int f = j[i];
int g = f - 97;
int h = 25 - g * 2;
j[i] += h;
}
Here's the situation:
I have 36 characters to choose from, a-z and 0-9.
char[] alphabet = "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray();
And using an index, we want to create all possible strings of length N, from N = 1 to N = 2.
A length of 1 is rather simple,
private String generateString(int index){
if (index < 36){
char word = alphabet[index];
return String.valueOf(word);
}
if ( index < 1332) {
//lost
}
}
But what if we wanted a length of 2, well we can assume that all words of length 2 will have an index of > 36 and < 1332 (36 + (36^2)). But I am lost on how to relate these indexes to a word with length 2, and making sure all possible word combinations are hit.
I think there is a mathematical way to accomplish this, but I am just not seeing it.
I'm not sure if I got your question right. Do you want all combinations of letters in various string lengths (like in a brute force attack)? Then this might help you.
If your alphabet consists just of 0-z, then you can make use of Java's Integer.toString() method providing a radix of 36, and just do some counting and padding:
void start(int lengthFrom, int lengthTo) {
for (int length = lengthFrom; length <= lengthTo; length++) {
for (int i=0; i < Math.pow(36, length); i++) {
result(String.format("%" + length + "s", Integer.toString(i, 36)).replace(' ', '0'));
}
}
}
void result(String s) {
System.out.println(s);
}
If you need more flexibility in regard to your alphabet, check this code. Here you can add whatever characters, because it just fills them recursively from left to right:
char[] alphabet = "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray();
void start(int lengthFrom, int lengthTo) {
for (int length = lengthFrom; length <= lengthTo; length++) {
char[] chars = new char[length];
fill(chars, 0);
}
}
void fill(char[] chars, int pos) {
if (chars.length == pos) {
result(new String(chars));
return;
}
for (char c : alphabet) {
chars[pos] = c;
fill(chars, pos+1);
}
}
void result(String s) {
System.out.println(s);
}
This method uses recursion. All recursive algorithms can be transformed to iterative algorithms; which usually consume less memory but are also less easy to read.
If you want an "index" for your Strings, you could build it using the result() method as the passed strings are ordered.
Oh, you're not talking about this, right?
Integer.parseInt(word, 36);
Integer.toString(index, 36);
So that
Integer.parseInt("1z", 36); // int(71)
Integer.toString(71, 36); // "1z"
For the two letter words, create a mapping [1,2,...,1296] -> ["00","01",...,"zz"] by folding the 1d index into a 2d one of size 36, ie. [1,2,...,1296] -> [(1,1), (2,1), (3,1), ..., (36,36)]:
private String generateTwoLetterString(final int index) {
if(index > 1296)
throw new IndexOutOfBoundsException("index is greater than 1296");
int j = (int) Math.ceil(index/36f);
int i = index % 36 == 0 ? 36 : index % 36;
return String.format("%s%s", alphabet[j-1], alphabet[i-1]);
}
I have the following piece of Java code and while debugging in Eclipse, Windows 7, the variable 'xoredChar' shows no value at all, not null, not '', nothing.
char xoredChar = (char) (stringA.charAt(j)^stringB.charAt(j));
Why is that? I need to understand how can I do this xor operation between two characters in java. What am I missing?
Well, if the strings are equal you'll get back a \0 which is not a printable character. Try something like this,
String stringA = "A";
String stringB = "A";
int j = 0;
char xoredChar = (char) (stringA.charAt(j) ^ stringB.charAt(j));
System.out.printf("'%c' = %d\n", xoredChar, (int) xoredChar);
Output is
' ' = 0
If stringA and stringB are identical, then the XOR operation will yield xoredChar = 0.
A 0 is probably showing in your IDE as nothing since 0 is used as a string terminator in most instances.
As mentioned by the other answers, xoring the same characters results in a \0 value, which has no visual representation. Perhapse you are interested in a small application, which gives you and idea how XOR works on your strings:
public class Example {
public static void main(String[] args) {
String a = "abcde";
String b = a;
for (int idx = 0; idx < b.length(); idx++) {
System.out.printf("xoring <%s> [%s] with <%s> [%s]\n",
a.charAt(0), toBinaryString(a.charAt(0)),
b.charAt(idx), toBinaryString(b.charAt(idx)));
int c = (a.charAt(0) ^ b.charAt(idx));
System.out.printf("result is <%s> [%s]\n",
(char) c, toBinaryString(c));
}
}
}
Have fun!
This question already has answers here:
Putting char into a java string for each N characters
(12 answers)
Closed 6 years ago.
What's the best way to insert a - (dash/minus character) after every 8 characters in a Java String, starting from the right?
Examples:
1111 -> 1111
111111111 -> 1-11111111
1111111111111111 -> 11111111-11111111
100001111111111111111 -> 10000-11111111-11111111
My attempt, to show that I have tried doing it myself (a comment below asks: "is this homework?":
import junit.framework.TestCase;
public class InsertCharacterAfterEveryNCharacters extends TestCase {
public static String insertSpacerAfterNCharactersFromTheRight(char spacer,
int spacing, String string) {
final int length = string.length();
final int newStringCapacity = length + (int) Math.ceil(length / (double) spacing);
StringBuilder stringBuilder = new StringBuilder(newStringCapacity);
for (int i = length - 1; i >= 0; i--) {
stringBuilder.append(string.charAt(i));
if (i % spacing == 0 && i > 0) {
stringBuilder.append(spacer);
}
}
return stringBuilder.toString();
}
public static void testInsertSpacerAfterNCharactersFromTheRight() {
assertEquals("", insertSpacerAfterNCharactersFromTheRight('-', 8, ""));
assertEquals("1", insertSpacerAfterNCharactersFromTheRight('-', 8, "1"));
assertEquals("11", insertSpacerAfterNCharactersFromTheRight('-', 8, "11"));
assertEquals("11111111",
insertSpacerAfterNCharactersFromTheRight('-', 8, "11111111"));
assertEquals("1-11111111",
insertSpacerAfterNCharactersFromTheRight('-', 8, "111111111"));
assertEquals("11111111-11111111",
insertSpacerAfterNCharactersFromTheRight('-', 8, "1111111111111111"));
}
}
All answers seem a bit lot of code for what needs to be done. You could use a regular expression to do that.
Let's say you have a method that returns your formatted string.
A simple, clear example:
String myString = "00000000000111111111111100000000001111111000011000000";
String newString = myString.replaceAll("(.{8})(?!$)", "$1-");
return newString;
Above is equal to the following shorter notation:
return myString.replaceAll("(.{8})(?!$)", "$1-");
Another similar, short notation (in case of a fixed, hard-coded string):
return "00000000000111111111111100000000001111111000011000000".replaceAll("(.{8})(?!$)", "$1-");
Each piece of code resturns the following string:
00000000-00011111-11111111-00000000-00111111-10000110-00000
For more info on regular expressions, see for example http://www.regular-expressions.info/java.html
Hope this helps anyone in the future.
Edit note:
The last group doesn;t have 8 characters. However, if it would, it won't add another dash.
Build up a char[] from the original String:
String str = "100001111111111111111";
// add enough space for an additional "-" for every 8 chars:
char[] chars = new char[str.length() + (str.length() / 8)];
// this offset will give us the first "-" position from the LEFT:
int offset = str.length() % 8;
int idx = 0, strIdx = 0;
for (; strIdx < str.length(); idx++, strIdx++)
{
if (((strIdx % 8) == offset) && (strIdx != 0))
chars[idx++] = '-';
chars[idx] = str.charAt(strIdx);
}
String str2 = new String(chars);
System.out.println(str2);
Or you could use a StringBuilder, which could involve (length / 8) array copy operations:
StringBuilder str = new StringBuilder("100001111111111111111");
int idx = str.length() - 8;
while (idx > 0)
{
str.insert(idx, "-");
idx = idx - 8;
}
System.out.println(str.toString());
Output in either case:
10000-11111111-11111111
Note that this won't insert a hyphen at index 0, you'll need to adjust the code if that's necessary.
The above solutions are good but are very complicated and long, I wrote this and it works for your inputs.
public static String insertCharacterForEveryNDistanceFromRight(int distance, String original, char c){
StringBuilder sb = new StringBuilder();
char[] charArrayOfOriginal = original.toCharArray();
for(int ch = charArrayOfOriginal.length ; ch > 0 ; ch--){
if(ch % distance == 0 && ch != charArrayOfOriginal.length)
sb.append(c).append(charArrayOfOriginal[charArrayOfOriginal.length - ch]);
else
sb.append(charArrayOfOriginal[charArrayOfOriginal.length - ch]);
}
return sb.toString();
}
And call it like this...
String rightResult = InsertSpaces.insertCharacterForEveryNDistanceFromRight(8, "100001111111111111111", '-');
System.out.println(rightResult);
You cannot literally insert a - into an existing Java String because String are immutable. However, you can create a new String instance that meets your output format requirement.
Loop from the end index of your input string down to 0. For each iteration:
Insert the value at the current index to the beginning of a StringBuilder instance.
Use the modulo operator to see if you have inserted a multiple of 8 characters. If so, insert a dash.
If needed, use the "toString()" method of your StringBuilder instance to get a string.
Something like this perhaps?
for(int i = s.length() - 1; i > 0; i -= 8)
{
s = new StringBuffer(s).insert(i, "-").toString();
i--;
}