关于java:替换和转换字符串

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
   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());
   }