Replacing and converting strings
有一个类似于解密的代码,其中引入了一个字符串,然后用一个双数字解密,字母可以是从A到J,分别是A=0,B=1…j=9。这个程序有效,我想知道的是,也许有一个最简单的方法来实现这个目标?我在Java中是新的,目前还不知道所有的特性。代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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)); } } |
从密码学的角度来看,你所描述的是替换密码。我甚至不再考虑这种加密,更像是编码(见这里)。
有字符串添加到字符串中。当你做类似的事情时
1 | c += k; |
Java实际上在做的是创建一个新的字符串对象,并将C中的指针更改为新对象。多年来,在创建和丢弃短期对象时,JVM已经变得更好了,但这仍然非常低效。尝试改用StringBuilder。
您还通过ConversionTable执行顺序搜索,这意味着您的整个算法是一个O(n^2)操作(请参见此处)(对于吹毛求疵的人,它实际上是O(m*n),但这对我来说已经足够接近了)。对于这么小的桌子来说完全无关紧要,但如果可能的话,避免做那样的事情。另外,当语言中的某些东西想为你做这件事时,你自己写这件事没有什么意义(这将是一个反复出现的主题)。您的项是有序的,因此我们可以利用数组中的binarysearch()实现之一。我会稍微设计一下用法,但这是为了说明。
您可以利用增强的for循环迭代大多数列表。我想说的是,如果您不能使用增强的for循环,那么您应该认真考虑使用while循环。
避免在开关以外的任何地方使用break语句。大多数人会认为他们是在同一条船上。
给你的变量取更多的描述性名称。你未来的自我会感谢你。
因此,通过我概述的更改,我们最终得到以下decrypt()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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; } |
这只是稍微好一点。如果我真的想做这样的事情,比较器将是一个单独的类,但这是用于说明的。
从编码的角度来看,这里有一个查找表。简单的实现是一个映射。传统上,初始化静态查找图有点难看,但是在这里检查IyaMaZOR0的答案,以便用Java 8来实现它。地图是一种自然的搜索结构,因此顺序并不重要。它还有一个很好的副作用,就是让小数点进入映射,从而消除一个if语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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; } |
在一般情况下,我会在这里停下来。但是您的查找列表是一个字符序列,它是一个整数序列。Java实际上把原始字符当作整数,这样就可以对它们进行数学运算。字符串甚至给了我们一个从字符串中获取字符的方法,这样我们就可以直接循环这些字符。我们必须再次处理if中的小数点,但它让我们完全摆脱了查找表。
1 2 3 4 5 6 7 8 9 10 11 |