检查一个字符串是否与另一个字符串相似

时间:2014-10-19 01:31:14

标签: java string

我做了一些研究,我发现主题是检查一个字符串是否是字符串中的子字符串,并选择最接近指定字符串的字符串,但我如何检查一个字符串是否类似于另一个并提供真/假响应?即:

String 1: JAVA IS A PROGRAMMING LANGUAGE
String 2: JAVA IS A PROGRAMMING LANGUAG X

这将返回“真实”

String 1: JAVA IS A PROGRAMMING LANGUAGE
String 2: I ATE THE CAKE

这将返回“false”

感谢。

3 个答案:

答案 0 :(得分:3)

你要问的是有点不重要的。你的答案的核心是另一个问题:

  

如何定义"类似"?

您需要指定一些规则来管理这个规则,以及与规则相关的一些阈值,我不确定您是否已经考虑过。

例如,下面是一个简单的解决方案(对我来说很简单或效率很高,我只是把它放在一起非常快,所以代码可能有点乱......我更关心回答这个问题......如果你愿意的话,你可以自己重构一下。有一个阈值%75,我在其中检查较小字符串中的字符数是否与较大字符串的%75%匹配(注意:java.lang.String是最终的,因此您无法扩展它) :

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MyString{
  private static final float THRESHOLD = (float) 0.75;

  private final Logger logger = Logger.getLogger(MyString.class.getName());

  private String str;
  private Map <Character, Integer> strMap;

  public MyString(String str){ //java.lang.String is final...
    this.str = str;
    this.strMap = this.generateCharMap(str);
  }

  public void executeTestForSophiaZhuang(){
    {
      MyString str1 = new MyString("JAVA IS A PROGRAMMING LANGUAGE");
      String str2 = "JAVA IS A PROGRAMMING LANGUAG X";
      logger.log(Level.INFO, "String {0}.isSimilar({1}) == {2}", new Object[]{
        str1.toString(), str2, str1.isSimilar(str2)});
    }
    {
      MyString str1 = new MyString("JAVA IS A PROGRAMMING LANGUAG X");
      String str2 = "JAVA IS A PROGRAMMING LANGUAGE";
      logger.log(Level.INFO, "String {0}.isSimilar({1}) == {2}", new Object[]{
        str1.toString(), str2, str1.isSimilar(str2)});
    }
    {
      MyString str1 = new MyString("JAVA IS A PROGRAMMING LANGUAGE");
      String str2 = "I ATE THE CAKE";
      logger.log(Level.INFO, "String {0}.isSimilar({1}) == {2}", new Object[]{
        str1.toString(), str2, str1.isSimilar(str2)});
    }
    {
      MyString str1 = new MyString("I ATE THE CAKE");
      String str2 = "JAVA IS A PROGRAMMING LANGUAGE";
      logger.log(Level.INFO, "String {0}.isSimilar({1}) == {2}", new Object[]{
        str1.toString(), str2, str1.isSimilar(str2)});
    }
  }

  @Override
  public String toString(){
    return this.str;
  }

  private Map <Character, Integer> generateCharMap(String str){
    Map <Character, Integer> map = new HashMap<>();
    Integer currentChar;
    for(char c: str.toCharArray()){
      currentChar = map.get(c);
      if(currentChar == null){
        map.put(c, 1);
      } else {
        map.put(c, currentChar+1);
      }
    }
    return map;
  }

  public boolean isSimilar(String compareStr){
    Map <Character, Integer> compareStrMap = this.generateCharMap(compareStr);
    Set <Character> charSet = compareStrMap.keySet();
    int similarChars = 0;
    int totalStrChars = this.str.length();
    float thisThreshold;

    if(totalStrChars < compareStrMap.size()){
      totalStrChars = compareStr.length();
    }

    Iterator it = charSet.iterator();
    char currentChar;
    Integer currentCountStrMap;
    Integer currentCountCompareStrMap;
    while(it.hasNext()){
      currentChar = (Character)it.next();
      currentCountStrMap = strMap.get(currentChar);
      if(currentCountStrMap != null){
        currentCountCompareStrMap = compareStrMap.get(currentChar);
        if (currentCountCompareStrMap >= currentCountStrMap){
          similarChars += currentCountStrMap;
        } else {
          similarChars += currentCountCompareStrMap;
        }
      } 
    }

    thisThreshold = ((float) similarChars)/((float) totalStrChars);
    Logger.getLogger(MyString.class.getName()).log(Level.INFO, "similarChars: {0}, totalStrChars: {1}, thisThreshold: {2}", new Object[]{similarChars, totalStrChars, thisThreshold});
    if(thisThreshold > THRESHOLD){
      return true;
    }
    return false;
  }
}

我认为你想要做的是在尝试定义isSimilar方法之前定义类似的东西。

答案 1 :(得分:2)

有很多方法可以确定两个字符串的相似性。其中最常见的是edit distanceLevenshtein distance的一个例子(并且有几种变体和其他方法 - 在维基百科上查看Category:String similarity measures)。< / p>

Levenshtein距离计算将一个字符串更改为另一个字符串所需的更改次数。例如:

JAVA IS A PROGRAMMING LANGUAGE
JAVA IS A PROGRAMMING LANGUAG X

的编辑距离为2:'E'更改为''并插入'X'。

kitten
sitting

的编辑距离为3:'k'为's','e'为'i'并插入'g'。

然后您将要编写的函数可能会有boolean similar(int threshold, String foo, String bar)的原型,其中阈值是允许的最大更改次数,foo和bar是您要比较的两个字符串。

如果您正在对单个字符串进行 批次 比较,您可能会考虑构建一个Levenshtein automaton,这是一种特殊类型的有限自动机,它接受一个字符串,如果它在aotma自动机构建的字符串的某个编辑距离内。

答案 2 :(得分:1)

在java中没有设置这样做的功能,所以你必须自己构建一个。你完全解决这个问题的方式取决于你想要达到的相似性的极限。

我将采用的方法是利用java提供的split函数,这样你就可以迭代句子中的每个单词。然后简单地将每个字符与另一个句子中的每个单词进行比较。

创建某种比例以进行失败或传递,如上所述,这将取决于您希望它的相似程度。

如果您不了解如何使用java中的字符串,请浏览Here

编辑:您可能感兴趣的还有一些不同的算法in another thread,这是One in use的更具体的例子