【问题标题】:how to implement near matches of strings in java?如何在java中实现字符串的近似匹配?
【发布时间】:2012-10-23 05:08:44
【问题描述】:

各位程序员们好,

我想就字符串的近似匹配寻求一些帮助。

目前,我有一个存储描述字符串的程序,用户可以通过完全或部分输入来搜索描述。

我想实现近似匹配搜索。例如,实际描述是“hello world”,但用户错误地输入了搜索“hello eorld”。程序应该能够向用户返回“hello world”。

我尝试查看模式和匹配来实现它,但它需要一个正则表达式来匹配字符串,因此我的描述没有常规模式。我也尝试过 string.contains,但它似乎也不起作用。以下是我尝试实现的部分代码。

    ArrayList <String> list = new ArrayList<String>();
    list.add("hello world");
    list.add("go jogging at london");
    list.add("go fly kite");
    Scanner scan = new Scanner(System.in);

    for(int i = 0; i < list.size(); i++){
      if(list.get(i).contains(scan.next())) {
         System.out.println(list.get(i));
      }
    }

其他程序员可以帮我解决这个问题吗?

【问题讨论】:

    标签: java string comparison string-matching lcs


    【解决方案1】:

    Levenshtein distance 能够限定两个字符串之间的差异

    这是一个实现taken form here

    public class LevenshteinDistance {
       private static int minimum(int a, int b, int c) {
          return Math.min(Math.min(a, b), c);
       }
    
       public static int computeLevenshteinDistance(
          CharSequence str1,
          CharSequence str2 )
       {
          int[][] distance = new int[str1.length() + 1][str2.length() + 1];
    
          for (int i = 0; i <= str1.length(); i++)
             distance[i][0] = i;
          for (int j = 1; j <= str2.length(); j++)
             distance[0][j] = j;
    
          for (int i = 1; i <= str1.length(); i++)
             for (int j = 1; j <= str2.length(); j++)
                distance[i][j] =
                   minimum(
                      distance[i - 1][j] + 1,
                      distance[i][j - 1] + 1,
                      distance[i - 1][j - 1] +
                         ((str1.charAt(i - 1) == str2.charAt(j - 1)) ? 0 : 1));
    
          return distance[str1.length()][str2.length()];
       }
    }
    

    【讨论】:

    • 关于你的实现:我会添加一些空字符串测试。如果 str1 为空,则距离为 str2.length()(反之亦然)
    • 要找到“相似”的字符串,这似乎是最好的解决方案。将两个字符串都设为小写通常会更好。
    【解决方案2】:

    Levenstein Distance 可能对这个问题有用。 Apache Commons Lang StringUtils 有一个实现。
    另外,如果您想了解字符串的不同之处,StringUtils 中的 difference 方法可能会很有趣。

    【讨论】:

    • 我刚开始输入这个:-)
    【解决方案3】:

    您可以使用 LCS(最长公共子序列)查看这些: http://en.wikipedia.org/wiki/Longest_common_subsequence_problem

    public class LCS {
    
        public static void main(String[] args) {
            String x = StdIn.readString();
            String y = StdIn.readString();
            int M = x.length();
            int N = y.length();
    
            // opt[i][j] = length of LCS of x[i..M] and y[j..N]
            int[][] opt = new int[M+1][N+1];
    
            // compute length of LCS and all subproblems via dynamic programming
            for (int i = M-1; i >= 0; i--) {
                for (int j = N-1; j >= 0; j--) {
                    if (x.charAt(i) == y.charAt(j))
                        opt[i][j] = opt[i+1][j+1] + 1;
                    else 
                        opt[i][j] = Math.max(opt[i+1][j], opt[i][j+1]);
                }
            }
    
            // recover LCS itself and print it to standard output
            int i = 0, j = 0;
            while(i < M && j < N) {
                if (x.charAt(i) == y.charAt(j)) {
                    System.out.print(x.charAt(i));
                    i++;
                    j++;
                }
                else if (opt[i+1][j] >= opt[i][j+1]) i++;
                else                                 j++;
            }
            System.out.println();
    
        }
    
    }
    

    其他解决方案是Aho–Corasick string matching algorithm 请参阅: Fast algorithm for searching for substrings in a string

    【讨论】:

    • 虽然我不知道这个方法是如何工作的,但我会去看看它并想出我的方法来实现它。谢谢 SjB :D
    猜你喜欢
    • 2011-05-11
    • 2013-07-10
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 2016-03-28
    • 2011-03-03
    相关资源
    最近更新 更多