【问题标题】:Java: alternative to String.contains that can return similarityJava:可以返回相似性的 String.contains 的替代品
【发布时间】:2022-01-05 01:58:40
【问题描述】:

我有三个字符串

String a = Hello, how are you doing?
String b = Can I as you something?
String c = Hello, how are you doing? Can I ask you something?

我的目标是评估字符串 c 是否是字符串 a 和 b 的合并。 请注意,字符串 b 中有一个错字,其中“as”应该是“ask”。

目前的逻辑是(伪代码):

if 
  String c contains String a AND String b
then 
  merge = true

我遇到的问题是,如果在合并过程中字符串 c 有轻微变化,则 String.contains() 不再有效,因为它在检查字符串 b 时返回 false。

是否有可能/想法使用替代且有效的示例?

我尝试使用字符串相似度(Jaccard 等),但由于 a、b 和 c 的大小可能不同,因此它们无法正常工作,因此很容易/可能获得正确的相似度百分比。

【问题讨论】:

  • 嗨@deHaar,请阅读整个问题,这部分很重要“我遇到的问题是,如果在合并过程中字符串 c 有轻微变化,则 String.contains() 不更长时间有效,因为它在检查字符串 b 时返回 false。"
  • 因此 String.contains 由于更改而无法正常工作,错字只是一个示例,所以我正在寻找一种替代方法,其中与 String.contains 类似的函数可以在特定条件下返回 true差异 %,或者简单地返回一个 %。
  • 哦,当然... ;-) 您可以尝试一些相似性算法,例如 Levenshtein 距离或类似算法,并为结果定义一个容差水平。
  • 这就是我现在尝试做的事情,但没有取得太大的成功:(。事实上,我有一个包含文本节点的 XML 树,这使它变得更加复杂。
  • 这显然不是一个小问题。根据性能限制,您可能必须检查为您提供有关两个字符序列相似性信息的算法组合。也有汉明距离,但不幸的是仅适用于相同长度的Strings,这在您的上下文中似乎不太可能发生。

标签: java string contains similarity sentence-similarity


【解决方案1】:

没有任何内置函数(我发现)可以做到这一点,但我想出了一些希望适合你需要的东西。你显然可以改变它(我试图让它尽可能干净)

第一步:我们需要一个函数,它接收两个字符串并返回两者的差异数。我想出了这个非常简单的功能:

public static int getNumberDifferences(String a, String b)
{
    int maxLength = Math.max(a.length(), b.length());
    int minLength = Math.min(a.length(), b.length());
    int result = maxLength - minLength;//the difference in length between the two

    for(int i = 0; i < minLength; i++)
    {
        if(a.charAt(i) != b.charAt(i)) //If the characters are different
            result++; //Add one to the result
    }

    return  result;
}

所以简而言之,我们遍历字符串并在每次遇到差异时将差异数加一。 (注意一开始我取了两个字符串长度的差异,所以这也计算了大小的差异)

第 2 步:我们需要另一个函数来接收每个单词(在一个数组中)并返回它遇到的每个差异。为此我想出了另一个超级简单的函数:

    public static int getNumberDifferences(String[] a, String[] b)
{
    int result = 0;

    for(int i = 0; i < Math.min(a.length, b.length); i++)
    {
        result += getNumberDifferences(a[i], b[i]);
    }

    return result;
}

在这个函数中,我们简单地将字符串中每个单词之间的所有差异相加。

最后,我们显示:

    public static void main(String[] args)
{
    String a = "Hello, how are you doing?" ;
    String b = "Can I ask you something?";
    String c = "Hello, how are you doing? Can I ask you something?";

    int differences = getNumberDifferences(
            (a + " " + b) //Join the two strings with a space in the middle
                    .split(" "), //Split them to take every word
            c.split(" ")); //Split c as well

    System.out.println(differences);
}

所以最后的代码是这样的:

public class Main {

public static void main(String[] args)
{
    String a = "Hello, how are you doing?" ;
    String b = "Can I ask you something?";
    String c = "Hello, how are you doing? Can I ask you something?";

    int differences = getNumberDifferences(
            (a + " " + b) //Join the two strings with a space in the middle
                    .split(" "), //Split them to take every word
            c.split(" ")); //Split c as well

    System.out.println(differences);
}

public static int getNumberDifferences(String[] a, String[] b)
{
    int result = 0;

    for(int i = 0; i < Math.min(a.length, b.length); i++)
    {
        result += getNumberDifferences(a[i], b[i]);
    }

    return result;
}

public static int getNumberDifferences(String a, String b)
{
    int maxLength = Math.max(a.length(), b.length());
    int minLength = Math.min(a.length(), b.length());
    int result = maxLength - minLength; //the difference in length between the two

    for(int i = 0; i < minLength; i++)
    {
        if(a.charAt(i) != b.charAt(i)) //If the characters are different
            result++; //Add one to the result
    }

    return  result;
}

}

如果这有帮助,请告诉我:)

【讨论】:

    【解决方案2】:

    在cmets中的正确标记,你必须与Levenshtein distance比较。

    您想使用相似性百分比来比较 2 个字符串,因此我们可以将此百分比作为字符串之间的关系距离与参考字符串的长度相关联。因此,如果我们要求 100% 的相似性,我们的字符串必须绝对相等,并且字符串之间的距离为 0。相反:如果我们要求 100% 的相似性,我们的字符串必须绝对不同,并且我们的距离几乎作为参考字符串的长度(或更多)。

    我将相似度百分比命名为allowedDiscrepancy,因为它提供的信息更多。所以,我的代码有方法 distance 用于计算参考字符串和另一个之间的距离和 compareWithDiscrepancy 方法,以进行关联。检查一下,它可以工作。

    public class StringUtils {
        public static void main(String[] args) {
            final String a = "Hello, how are you doing?";
            final String b = "Can I as you something?";
            final String c = "Hello, how are you doing? Can I ass you something?";
    
            // allowedDiscrepancy = 1.0 (100%) - strings might be absolutely different
            //So, we have 2 strings with little difference, so it must be return "true"
            assertTrue(compareWithDiscrepancy(c, String.format("%s %s", a, b), 1.0));
            // allowedDiscrepancy = 0.0 (0%) - strings must be absolutely equals
            //So, we have 2 strings with little difference, but more than 0, so it must be return "false"
            assertFalse(compareWithDiscrepancy(c, String.format("%s %s", a, b), 0.0));
    
            final String sameA = "Hello.";
            final String sameB = "How are you?";
            final String sameC = String.format("%s %s", sameA, sameB);
    
            // allowedDiscrepancy = 1.0 (100%) - strings might be absolutely different
            //So, we have 2 strings absolutely equals, so it must be return "true"
            assertTrue(compareWithDiscrepancy(sameA, String.format("%s %s", sameA, sameB), 1));
            // allowedDiscrepancy = 0.0 (0%) - strings must be absolutely equals
            //So, we have 2 strings absolutely equals, so it must be return "true" too
            assertTrue(compareWithDiscrepancy(sameC, String.format("%s %s", sameA, sameB), 0));
    
            final String differentA = "Part 1.";
            final String differentB = "Part 2.";
            final String differentC = "Absolutely different string";
    
            // allowedDiscrepancy = 1.0 (100%) - strings might be absolutely different
            //So, we have 2 absolutely different strings, so it must be return "true"
            assertTrue(compareWithDiscrepancy(differentC, String.format("%s %s", differentA, differentB), 1));
            // allowedDiscrepancy = 0.0 (0%) - strings must be absolutely equals
            //So, we have 2 absolutely different strings, so it must be return "false" too
            assertFalse(compareWithDiscrepancy(differentC, String.format("%s %s", differentA, differentB), 0));
    
            System.out.println("Done!");
        }
    
        public static boolean compareWithDiscrepancy(final String referenceString, final String testedString, double allowedDiscrepancy) {
            if (allowedDiscrepancy < 0) allowedDiscrepancy = 0;
            if (allowedDiscrepancy > 1) allowedDiscrepancy = 1;
    
            int distance = distance(referenceString, testedString);
            double realDiscrepancy = distance * 1.0 / referenceString.length();
            if (realDiscrepancy > 1) realDiscrepancy = 1;
            return allowedDiscrepancy >= realDiscrepancy;
        }
    
        static int distance(String x, String y) {
            int[][] dp = new int[x.length() + 1][y.length() + 1];
    
            for (int i = 0; i <= x.length(); i++) {
                for (int j = 0; j <= y.length(); j++) {
                    if (i == 0) {
                        dp[i][j] = j;
                    } else if (j == 0) {
                        dp[i][j] = i;
                    } else {
                        dp[i][j] = min(dp[i - 1][j - 1]
                                + cost(x.charAt(i - 1), y.charAt(j - 1)),
                            dp[i - 1][j] + 1,
                            dp[i][j - 1] + 1);
                    }
                }
            }
    
            return dp[x.length()][y.length()];
        }
    
        public static int cost(char a, char b) {
            return a == b ? 0 : 1;
        }
    
        public static int min(int... numbers) {
            return Arrays.stream(numbers)
                .min().orElse(Integer.MAX_VALUE);
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-29
      • 1970-01-01
      • 2010-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多