1

Have a code that does something like decrypting where a string is introduced and then is decrypted in a double number, the letters can be from a to j and respectively a = 0, b = 1 ... j = 9. The program works, all I want to know maybe there is a easiest way to achieve this ? I am new in java and for the moment don't know all the features. Code:

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.Double;
public class Decrypt 
{   
    private static String conversionTable[][] = {
        {"a", "0"},
        {"b", "1"},
        {"c", "2"},
        {"d", "3"},
        {"e", "4"},
        {"f", "5"},
        {"g", "6"},
        {"h", "7"},
        {"i", "8"},
        {"j", "9"},
    };
    private static Scanner scanner;

    public static double decrypt(String encryptedNumber) 
    {
        String c = "";
        int i = 0;
        String[] s = encryptedNumber.split("");

        for(int j = 0; j < 2; j++) {
            if(c.length() == s.length)
                break;

            for(int k = 0; k < 9; k++) {
                if(c.length() == s.length)
                    break;
                if(conversionTable[k][j].equalsIgnoreCase(s[i])){
                     c += k;
                        i++;
                }else if(s[i].equalsIgnoreCase(".")){
                    c += ".";
                    i++;
                }
            }
            j--;
        }

        double d = Double.parseDouble(c);
        return d;
    }

    public static void main(String arg[])
    {   
        scanner = new Scanner(System.in);
        System.out.println("Enter the string to decrypt:");
        String input=scanner.next();
        System.out.println("Number after decryption is:"+decrypt(input));
    }
}
zajonc
  • 1,935
  • 5
  • 20
  • 25
JONNI CAREYN
  • 97
  • 1
  • 2
  • 8
  • 1
    Well, char is just a data type; and char values ... can be expressed as numbers, like here: https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html ... so, assuming that you are only allowing ascii characters ... you dont need a map, you can do simple computations. Left as exercise to the reader. – GhostCat Aug 10 '16 at 20:30

1 Answers1

0

From a cryptography point of view what you're describing is a substitution cipher. I wouldn't even consider this encryption anymore, more like encoding (see here).

You have Strings adding to Strings. When you do something like

c += k;

what Java is actually doing there is creating a new String object and changing the pointer in c to that new object. The JVM has gotten much better over the years when creating and discarding short-lived objects but this is still very inefficient. Try using a StringBuilder instead.

You're also performing a sequential search through your conversionTable which means your whole algorithm is a O(n^2) operation (see here) (for the nitpickers, it's actually O(m*n) but that's close enough for me). Totally irrelevant for such a small table, but avoid doing things like that if possible. Plus, there's little point in writing it yourself when something in the language wants to do it for you (this will be a recurring theme). Your items are in order so we can take advantage of one of the binarySearch() implementations in Arrays. I'll contrive the usage a little bit, but it's for the purpose of illustration.

You can take advantage of the enhanced for loop to iterate through most lists. I'd go so far as to say that if you can't use the enhanced for loop then you should seriously consider a while loop instead.

Avoid using break statement in anything other than a switch. Most people will consider them to be in the same boat a the goto.

And give your variables more descriptive names. Your future self will thank you.

So with the changes I've outlined we end up with the following decrypt() method:

public static double decrypt(String encryptedNumber) {
   StringBuilder builder = new StringBuilder();
   int i = 0;
   String[] encNumElements = encryptedNumber.toLowerCase().split("");
   for (String element : encNumElements) {
      int foundAt = Arrays.binarySearch(conversionTable, new String[]{element, ""}, new Comparator<String[]>() {
            @Override
            public int compare(String[] arg0, String[] arg1) {
               return arg0[0].compareTo(arg1[0]);
            }               
      });
      if (foundAt >= 0) {
         builder.append(conversionTable[foundAt][1]);
      } else {
         // assuming a decimal point here since it's not on the list
         builder.append('.');
      }
   }

   double d = Double.parseDouble(builder.toString());
   return d;
}

This is only a little better. If I really wanted to do something like this the Comparator would be a separate class but this works for illustration.

From a coding point of view, what you have here is a lookup table. The easy implementation is a Map. Traditionally, initializing a static lookup Map is kinda ugly, but check out i_am_zero's answer here for a neater way of doing it with Java 8. A Map is a natural search structure so order is not important. It also has the nice side effect of letting up put the decimal point into the Map and thus eliminate an if statement.

   private static final Map<String, String> conversionMap = Stream.of(
         new SimpleEntry<>("a", "0"),
         new SimpleEntry<>("b", "1"),
         new SimpleEntry<>("c", "2"),
         new SimpleEntry<>("d", "3" ),
         new SimpleEntry<>("e", "4"),
         new SimpleEntry<>("f", "5"),
         new SimpleEntry<>("g", "6"),
         new SimpleEntry<>("h", "7" ),
         new SimpleEntry<>("i", "8"),
         new SimpleEntry<>("j", "9"),
         new SimpleEntry<>(".", "."))
         .collect(Collectors.toMap((se) -> se.getKey(), (se) -> se.getValue()));

   public static double decrypt(String encryptedNumber) {
      StringBuilder builder = new StringBuilder();
      String[] encNumElements = encryptedNumber.toLowerCase().split("");
      for (String element : encNumElements) {         
            builder.append(conversionMap.get(element));
      }

      double d = Double.parseDouble(builder.toString());
      return d;
   }

Something like this is where I would stop in the general case. But your lookup list is a sequence of characters into a sequence of integers. Java actually does treat primitive characters as integers so you can do math on them. String even gives us a method to get characters from a String so we can loop through them directly. We have to deal with the decimal point in an if again, but it lets us get rid of the lookup table entirely.

   public static double decrypt(String encryptedNumber) {
      StringBuilder builder = new StringBuilder();
      for (char ch : encryptedNumber.toLowerCase().toCharArray()) {
         if (ch == '.') {
            builder.append('.');
         } else {
            builder.append(ch - 'a');
         }
      }
      return Double.parseDouble(builder.toString());
   }
Community
  • 1
  • 1
Jose Ferrer
  • 1,188
  • 1
  • 7
  • 9