如何在java中实现字符串的近似匹配?

Posted

技术标签:

【中文标题】如何在java中实现字符串的近似匹配?【英文标题】:how to implement near matches of strings in 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));
      
    

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

【问题讨论】:

【参考方案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

以上是关于如何在java中实现字符串的近似匹配?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel 中实现 GoogleOR-Tool?特别是对于“作为最小成本流算法的分配”(Java)

你如何在 C 中实现一个类? [关闭]

正则表达式:如何在 PL/SQL 中实现负向后查找

如何在 iPhone 应用中实现手写识别功能?

Scala - 如何在 Spark 的 map 函数中实现 Try

在JAVA中实现数字的倒序输出