I currently do a lot of conversions from int into a base36 string (70%~ of programs time).
Are there any obvious optimisations to this code?
public static final String alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
public static StringBuilder b = new StringBuilder();
public static String sign = "";
public static String convertToBase36(int number)
{
if (number == 0)
{
return "0";
}
b.delete(0, b.length());
sign = "";
if (number < 0)
{
sign = "-";
number = -number;
}
int i = 0;
int counter = 10;
while (number != 0 && counter > 0)
{
counter--;
i = number % 36;
number = (number - i)/36;
b.append(alphabet.charAt(i));
}
return sign + b.reverse().toString();
}
You can use:
String s = Integer.toString(100, 36);
int i = Integer.parseInt("2s", 36);
Easier to maintain, and probably well optimized.
Related
So I have written a Java Program (Which I have attached the code for below) for a cryptographic cipher I designed (based on the SPN cipher but with a few modifications). Anyways, when I run my program, the code instantly stops and I receive a java.lang.ThreadDeath error. I have tried even adding a print statement to the very beginning (as in first line) of my main method (so it was the first thing processed by my program), but I had no luck, Java stopped before my print statement could even run.
Here is my code:
package SSPN;
import java.io.*;
import java.util.*;
public class Main throws IOException{
public static final int NUM_ROUNDS = 1;
public static final File f = new File("sBoxes.txt");
//Need better comments!!
//For each character, prints out a binary string of length 7. Does zero - padding!
public static String[] plaintextToCharacterBinarySequence(String plaintext)
{
//Getting int values
int[] charRepresentations = new int[plaintext.length()];
for (int i = 0; i < charRepresentations.length; i++)
{
char ch = plaintext.charAt(i);
int asciiValue = (int)ch;
charRepresentations[i] = asciiValue;
}
String[] binValues = new String[charRepresentations.length];
System.out.print("Binary values are: ");
for (int i = 0; i < binValues.length; i++)
{
String str = Integer.toBinaryString(charRepresentations[i]);
StringBuilder sb = new StringBuilder(str);
if (str.length() !=7)
{
int DIFF = 7 - str.length(); //As it is an Ascii Value, must be less than length 7
for (int j = 7; j > (7 - DIFF); j--)
{
sb.insert(0,"0");
}
}
str = sb.toString();
binValues[i] = str;
System.out.print(binValues[i] + " ");
}
System.out.println();
return binValues;
}
public static String binarySequenceToString(String[] sequence)
{
StringBuilder sb = new StringBuilder();
for (int i =0; i < sequence.length; i++)
{
int val = Integer.parseInt(sequence[i], 2);
char ch = (char) val;
sb.append(ch);
}
return sb.toString();
}
/*We define an instance of the affine cipher (for extra security), with a = length of message,b = ascii value of 1st character.
m = 128. Then, we convert the output to (zero-padded) 7-bit binary number, and store the result as the output of a hash
table (where the input binary number is the key)*/
public static HashMap<String, String> defineandStoreSBoxes(File f, int lengthOfMessage, int firstAsciiValue) throws FileNotFoundException, IOException
{
BufferedReader br = new BufferedReader(new FileReader(f));
HashMap<String, String> hm = new HashMap <String, String>();
String currentSBox;
while ((currentSBox = br.readLine()) != null)
{
int base10Val = Integer.parseInt(currentSBox, 2);
int encryptedOutput = lengthOfMessage * base10Val + firstAsciiValue; //(LIMITATION: Without modding by 128, encryptedOutput Cannot exceed Integer.MAX_VALUE)
String binOutput = Integer.toBinaryString(encryptedOutput);
StringBuilder sb = new StringBuilder(binOutput);
if (binOutput.length() !=7)
{
int DIFF = 7 - binOutput.length(); //As it is an Ascii Value, must be less than length 7
for (int j = 7; j > (7 - DIFF); j--)
{
sb.insert(0,"0");
}
}
binOutput = sb.toString();
hm.put(currentSBox, binOutput);
}
br.close();
return hm;
}
//This method performs bitwise XOR on each block of the plaintext and the bits of the round key (which are the same size)
public static String[] xorSubkey(String[] currentText, String roundKey )
{
for (int i =0; i < roundKey.length(); i++)
{
StringBuilder sb = new StringBuilder();
String binStr = currentText[i];
for (int j =0; j < 7; j++)
{
int chCurrent = Character.getNumericValue(binStr.charAt(j)); //Either 0 or 1
int chKey = Character.getNumericValue(roundKey.charAt((1 * 7)+ j));
if (chCurrent == chKey)
{
sb.append("0");
}
else
{
sb.append("1");
}
}
currentText[i] = sb.toString();
}
return currentText;
}
public static String[] sBoxSubstitution(String[] currentText, HashMap <String,String> hm)
{
for (int i =0; i < currentText.length; i++)
{
String val = hm.get(currentText[i]);
currentText[i] = val;
}
return currentText;
}
public static String[] linTransform(String[] currentText)
{
int shift = currentText.length % 7;
for (int i =0; i < currentText.length; i++)
{
StringBuilder sb = new StringBuilder(currentText[i]);
String sub = currentText[i].substring(shift, 7);
sb.insert(0, sub);
sb.delete(currentText[i].length(), currentText[i].length() + (7 - shift));
currentText[i] = sb.toString();
}
return currentText;
}
public static String[] encrypt(String plaintext, String[] roundKeys) throws IOException
{
String[] binaryText = plaintextToCharacterBinarySequence(plaintext);
HashMap<String, String> hm = defineandStoreSBoxes(f, plaintext.length(), (int) plaintext.charAt(0));
String[] xoredSequence, substitutedSequence,transformedSequence = null;
//The first Num_Rounds -1 Rounds
for (int i =0; i < NUM_ROUNDS -1; i++)
{
xoredSequence = xorSubkey(binaryText, roundKeys[i]);
substitutedSequence = sBoxSubstitution(xoredSequence, hm);
transformedSequence = linTransform(substitutedSequence);
}
// the final round
xoredSequence = xorSubkey(transformedSequence, roundKeys[roundKeys.length - 2]); //Make sure this isnt null
substitutedSequence = sBoxSubstitution(xoredSequence, hm);
//Final xor Subkeying
String[] ciphertext = xorSubkey(substitutedSequence, roundKeys[roundKeys.length - 1]); //Make sure this isnt null
return ciphertext;
}
//DECRYPTING
public static String[] decrypt(String textToDecrypt, String[] roundKeys) throws IOException
{
String[] bitCiphertext = plaintextToCharacterBinarySequence(textToDecrypt);
HashMap<String, String> hm= defineandStoreSBoxes(f,textToDecrypt.length(), (int)textToDecrypt.charAt(0) ); //Make sure this is reversed
String[] xoredSequence, substitutedSequence,transformedSequence = null;
//Decrypting final ciphertext
String[] finalXOR = xorSubkey(bitCiphertext, roundKeys[roundKeys.length - 1]);
// Final round
substitutedSequence = reverseSBox(finalXOR, hm);
xoredSequence = xorSubkey(substitutedSequence, roundKeys[roundKeys.length - 2]);
//Reversing the loop order
for (int i = NUM_ROUNDS -1; i >= 0; i--)
{
transformedSequence = reverseLinTransform(substitutedSequence);
substitutedSequence = reverseSBox(transformedSequence, hm);
xoredSequence = xorSubkey(substitutedSequence, roundKeys[i]);
}
String[] plaintext = xoredSequence;
return plaintext;
}
public static String[] reverseSBox(String[] value, HashMap <String, String> hm)
{
for (int i =0; i < value.length; i++)
{
for (Map.Entry<String, String> entry : hm.entrySet())
{
if (value[i].equals(entry.getValue())) //Because s-boxes are bijective
{
value[i] = entry.getKey();
}
}
}
return value;
}
public static String[] reverseLinTransform(String[] value)
{
int shift = 7 - (value.length %7);
for (int i =0; i < value.length; i++)
{
StringBuilder sb = new StringBuilder(value[i]);
String sub = value[i].substring(shift, 7);
sb.insert(0, sub);
sb.delete(value[i].length(), value[i].length() + (7 - shift));
value[i] = sb.toString();
}
return value;
}
public static boolean isGoodRoundKey(String key, int plainTextLength)
{
if (plainTextLength == key.length() && key.length() % 7 ==0 && isBinary(key) ==true)
{
return true;
}
else
{
return false;
}
}
public static boolean isBinary(String number)
{
for (int i =0; i < number.length(); i++)
{
char c = number.charAt(i);
if (c != '0' && c != '1')
{
return false;
}
}
return true;
}
public static void main(String[] args) throws IOException
{
System.out.println("Inside main");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //Buffered reader will read in plaintext, and round keys
System.out.print("Enter the text that you would like to encrypt: ");
String plaintext = br.readLine();
int numChars = plaintext.length();//The total number of characters that make up this string
String[] roundKeys = new String[NUM_ROUNDS + 1];//Each box will have 7 bits
System.out.println("The cipher will encrypt for "+ NUM_ROUNDS + "rounds, so you will need to enter some round keys. ");
System.out.println("Each round key must be a sequence of zeroes and ones, and must be exactly seven times the length of the plaintext string");
//Storing all the round keys in the array!
for (int i =0; i <= NUM_ROUNDS; i++)
{
if (i ==0)
{
System.out.print("Enter the round key for the 1st round: ");
}
else if (i ==1)
{
System.out.print("Enter the round key for the 2nd round: ");
}
else if (i ==2)
{
System.out.print("Enter the round key for the 3rd round: ");
}
else if (i == NUM_ROUNDS)
{
System.out.print("Enter the round key that will be XORed at the very end of all the rounds ");
}
else
{
System.out.print("Enter the round key for the " + i+1 + "th round: ");
}
roundKeys[i] = br.readLine();
System.out.println();
/*Check to make sure the round key that is passed in is valid. If it is not, an error message will be printed to the user,
prompting them to enter a valid round key. This will loop indefinitely until a valid round key is entered.
*/
if (isGoodRoundKey(roundKeys[i],plaintext.length() ) !=true)
{
boolean isValid = false;
while(isValid == false)
{
System.out.println("ERROR: the key you entered is not a valid key for this cipher.");
System.out.println("Please enter another key: ");
String new_key = br.readLine();
if (isGoodRoundKey(new_key, plaintext.length()) ==true)
{
roundKeys[i] = new_key;
isValid = true;
}
}
}
}
br.close();
String[] bitCiphertext = encrypt(plaintext, roundKeys);
String ciphertext = binarySequenceToString(bitCiphertext);
System.out.println("The encryption of " + plaintext + " is: "+ ciphertext);
String[] discoveredBitPlaintext = decrypt(ciphertext, roundKeys);
String discoveredPlaintext = binarySequenceToString(bitCiphertext);
System.out.println("The encryption of " + ciphertext + " is: " + discoveredPlaintext);//Reverse order of round Keys
}
}
so I have a code that should multiplicate two Binary Numbers as String without using ParseInt. My code actually works by far but it's multiplicating as decimal numbers. Something in the part where it should do the addition is wrong.
Thanks for any kind of help!
public static String multiply(String binary1, String binary2)
String b1 = new StringBuilder(binary1).reverse().toString();
String b2 = new StringBuilder(binary2).reverse().toString();
int[] m = new int[binary1.length()+binary2.length()];
for (int i = 0; i < binary1.length(); i++) {
for (int j = 0; j < binary2.length(); j++) {
m[i+j] += (b1.charAt(i)-'0')*(b2.charAt(j)-'0');
}
}
StringBuilder sb = new StringBuilder();
for(int i=0; i < m.length; i++) {
int mod = m[i]%10;
int carry = m[i]/10;
if (i+1 < m.length) {
m[i + 1] = m[i + 1] + carry;
}
sb.insert(0, mod);
}
// delete leading zeros
while (sb.charAt(0) == '0' && sb.length() > 1) {
sb.deleteCharAt(0);
}
return sb.toString();
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("1. Faktor: ");
String input1 = scan.next("(0|1)*");
System.out.print("2. Faktor: ");
String input2 = scan.next("(0|1)*");
scan.close();
System.out.println("Ergebnis: " + multiply(input1, input2));
}
}
You may not use Integer.parseInt but nobody forbid you to implement your own parser:
private static int parseBinaryString(String s) {
int binary = 0;
for (int i = s.length() - 1, c; i >= 0; i--) {
binary <<= 1;
c = s.charAt(i);
if (c == '1') {
binary++;
} else if (c != '0') {
throw new NumberFormatException(s);
}
}
return binary;
}
Which can then be simply used like this in your multiply method:
private static String multiply(String a, String b) {
return Integer.toBinaryString(parseBinaryString(a) * parseBinaryString(b));
}
And if you can't use Integer.toBinaryString you can implement that method yourself:
private static String toBinaryString(int i) {
StringBuilder binary = new StringBuilder();
for (int t = i; t != 0; t >>= 1) {
binary.append((i & t) != 0 ? 1 : 0);
}
return binary.toString();
}
I am trying to use the LZW code provided by Princeton and modify it to vary the size of codeword from 9 to 16 bits. I am unsure of how to do this, but was thinking of maybe using a loop since the size needs to be increased when all codewords of the size before were used. I am just looking for a useful direction to go in, since this is an assignment that I am having trouble starting.
public class LZW {
private static final int R = 256; // number of input chars
private static final int L = 4096; // number of codewords = 2^W
private static final int W = 12; // codeword width
public static void compress() {
String input = BinaryStdIn.readString();
TST<Integer> st = new TST<Integer>();
for (int i = 0; i < R; i++)
st.put("" + (char) i, i);
int code = R+1; // R is codeword for EOF
while (input.length() > 0) {
String s = st.longestPrefixOf(input); // Find max prefix match s.
BinaryStdOut.write(st.get(s), W); // Print s's encoding.
int t = s.length();
if (t < input.length() && code < L) // Add s to symbol table.
st.put(input.substring(0, t + 1), code++);
input = input.substring(t); // Scan past s in input.
}
BinaryStdOut.write(R, W);
BinaryStdOut.close();
}
public static void expand() {
String[] st = new String[L];
int i; // next available codeword value
// initialize symbol table with all 1-character strings
for (i = 0; i < R; i++)
st[i] = "" + (char) i;
st[i++] = ""; // (unused) lookahead for EOF
int codeword = BinaryStdIn.readInt(W);
if (codeword == R) return; // expanded message is empty string
String val = st[codeword];
while (true) {
BinaryStdOut.write(val);
codeword = BinaryStdIn.readInt(W);
if (codeword == R) break;
String s = st[codeword];
if (i == codeword) s = val + val.charAt(0); // special case hack
if (i < L) st[i++] = val + s.charAt(0);
val = s;
}
BinaryStdOut.close();
}
public static void main(String[] args) {
if (args[0].equals("-")) compress();
else if (args[0].equals("+")) expand();
else throw new IllegalArgumentException("Illegal command line argument");
}
}
I have written the following code:
public String alphabets = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ#$%";
public Integer findBase(String input) {
int i = 0;
Integer base = 0;
Integer temp = 0;
while (i != input.length()) {
temp = alphabets.indexOf(input.charAt(i)) + 1;
if (temp > base) {
base = temp;
}
i ++;
}
public String convert(String input, Integer to_base, Integer from_base) {
int i;
Long base_ten = 0L;
Integer input_base = 0;
// If specified, then consider that base as input from base, or else,
// calculate the base of the number
if (from_base == 0) {
input_base = findBase(input);
} else {
input_base = from_base;
}
Integer power = 0;
Double temp_power = 0.0;
while (!input.equals("")) {
temp_power = Math.pow(input_base, power);
base_ten = base_ten + alphabets.indexOf(input.charAt(input.length() - 1)) * temp_power.intValue();
input = input.substring(0, input.length() - 1);
power = power + 1;
}
Long rem = 0L;
String result = "";
while (base_ten != 0L) {
rem = base_ten % to_base;
base_ten = base_ten / to_base;
result = result + alphabets.charAt(rem.intValue());
}
String reverse = new StringBuffer(result).reverse().toString();
return reverse;
}
Using the above code, it is possible to convert strings like say "suchin" (Base 31) to other bases. But whenever I use something larger, like say "suchind", I get an exception at the following line in above code:
result = result + alphabets.charAt(rem.intValue());
saying that the index is -1. When I dug a little deeper, I felt that rem.intValue() is somehow going negative (-1) for some large values. Not sure how to get this solved. Is there a way of converting between bases for large numbers in java?
BigInteger version of code is below:
public String convert(String input, BigInteger to_base, BigInteger from_base) {
int i;
BigInteger base_ten = new BigInteger("0");
BigInteger input_base = new BigInteger("0");
if (from_base.equals(BigInteger.valueOf(0))) {
input_base = BigInteger.valueOf(findBase(input));
} else {
input_base = from_base;
}
BigInteger power = new BigInteger("0");
BigInteger temp_power = new BigInteger("0");
BigInteger to_add = new BigInteger("0");
while (!input.equals("")) {
temp_power = input_base.pow(power.intValue());
to_add = BigInteger.valueOf(alphabets.indexOf(input.charAt(input.length() - 1)));
to_add = to_add.multiply(temp_power);
base_ten = base_ten.add(to_add);
input = input.substring(0, input.length() - 1);
power = power.add(BigInteger.valueOf(1));
}
BigInteger rem = new BigInteger("0");
String result = "";
while (!base_ten.equals(BigInteger.valueOf(0))) {
rem = base_ten.remainder(to_base);
base_ten = base_ten.divide(to_base);
result = result + alphabets.charAt(rem.intValue());
}
String reverse = new StringBuffer(result).reverse().toString();
return reverse;
}
The above code works fine now. Earlier I had done the following:
while( base_ten != BigInteger.valueOf(0)) {
Which was causing infinite loop, as apparently that was not the way to compare in BigIntegers :)
I have a problem wherein I have two strings, the length of one of which I will know only upon execution of my function. I want to write my function such that it would take these two stings and based upon which one is longer, compute a final string as under -
finalString = longerStringChars1AND2
+ shorterStringChar1
+ longerStringChars3and4
+ shorterStringChar2
+ longerStringChars5AND6
...and so on till the time the SHORTER STRING ENDS.
Once the shorter string ends, I want to append the remaining characters of the longer string to the final string, and exit. I have written some code, but there is too much looping for my liking. Any suggestions?
Here is the code I wrote - very basic -
public static byte [] generateStringToConvert(String a, String b){
(String b's length is always known to be 14.)
StringBuffer stringToConvert = new StringBuffer();
int longer = (a.length()>14) ? a.length() : 14;
int shorter = (longer > 14) ? 14 : a.length();
int iteratorForLonger = 0;
int iteratorForShorter = 0;
while(iteratorForLonger < longer) {
int count = 2;
while(count>0){
stringToConvert.append(b.charAt(iteratorForLonger));
iteratorForLonger++;
count--;
}
if(iteratorForShorter < shorter && iteratorForLonger >= longer){
iteratorForLonger = 0;
}
if(iteratorForShorter<shorter){
stringToConvert.append(a.charAt(iteratorForShorter));
iteratorForShorter++;
}
else{
break;
}
}
if(stringToConvert.length()<32 | iteratorForLonger<b.length()){
String remainingString = b.substring(iteratorForLonger);
stringToConvert.append(remainingString);
}
System.out.println(stringToConvert);
return stringToConvert.toString().getBytes();
}
You can use StringBuilder to achieve this. Please find below source code.
public static void main(String[] args) throws InterruptedException {
int MAX_ALLOWED_LENGTH = 14;
String str1 = "yyyyyyyyyyyyyyyy";
String str2 = "xxxxxx";
StringBuilder builder = new StringBuilder(MAX_ALLOWED_LENGTH);
builder.append(str1);
char[] shortChar = str2.toCharArray();
int index = 2;
for (int charCount = 0; charCount < shortChar.length;) {
if (index < builder.length()) {
// insert 1 character from short string to long string
builder.insert(index, shortChar, charCount, 1);
}
// 2+1 as insertion index is increased after after insertion
index = index + 3;
charCount = charCount + 1;
}
String trimmedString = builder.substring(0, MAX_ALLOWED_LENGTH);
System.out.println(trimmedString);
}
Output
yyxyyxyyxyyxyy
String one = "longwordorsomething";
String two = "short";
String shortString = "";
String longString = "";
if(one.length() > two.length()) {
shortString = two;
longString = one;
} else {
shortString = one;
longString = two;
}
StringBuilder newString = new StringBuilder();
int j = 0;
for(int i = 0; i < shortString.length(); i++) {
if((j + 2) < longString.length()) {
newString.append(longString.substring(j, j + 2));
j += 2;
}
newString.append(shortString.substring(i, i + 1));
}
// Append last part
newString.append(longString.substring(j));
System.out.println(newString);