जावा में समानता स्ट्रिंग तुलना


111

मैं एक दूसरे से कई तार की तुलना करना चाहता हूं, और उन लोगों को ढूंढता हूं जो सबसे समान हैं। मैं सोच रहा था कि क्या कोई पुस्तकालय, पद्धति या सर्वोत्तम अभ्यास है जो मुझे लौटाएगा जो तार अन्य तार के समान हैं। उदाहरण के लिए:

  • "द्रुत लोमड़ी कूद गई" -> "लोमड़ी कूद गई"
  • "द्रुत लोमड़ी कूद गई" -> "लोमड़ी"

यह तुलना वापस आएगी कि पहली दूसरी से अधिक समान है।

मुझे लगता है कि मुझे कुछ विधि की आवश्यकता है जैसे:

double similarityIndex(String s1, String s2)

कहीं ऐसा है क्या?

संपादित करें: मैं यह क्यों कर रहा हूँ? मैं एक स्क्रिप्ट लिख रहा हूं जो कुछ विरासत प्रणाली के आउटपुट के लिए एमएस प्रोजेक्ट फ़ाइल के आउटपुट की तुलना करता है जो कार्यों को संभालता है। क्योंकि विरासत प्रणाली में बहुत सीमित क्षेत्र चौड़ाई होती है, जब मूल्यों को जोड़ा जाता है तो विवरण संक्षिप्त होते हैं। मैं कुछ अर्ध-स्वचालित तरीका खोजना चाहता हूं कि एमएस प्रोजेक्ट से कौन सी प्रविष्टियां सिस्टम पर प्रविष्टियों के समान हैं ताकि मैं उत्पन्न कुंजी प्राप्त कर सकूं। इसमें कमियां हैं, क्योंकि इसे अभी भी मैन्युअल रूप से जांचना है, लेकिन यह बहुत सारे काम को बचाएगा

जवाबों:


82

हाँ, कई अच्छी तरह से प्रलेखित एल्गोरिदम हैं:

  • कोसाइन समानता
  • जैकार्ड समानता
  • पासा का गुणांक
  • मैचिंग समानता
  • समानता को ओवरलैप करें
  • आदि आदि

एक अच्छा सारांश ("सैम का स्ट्रिंग मेट्रिक्स") यहां पाया जा सकता है (मूल लिंक मृत है, इसलिए यह इंटरनेट पुरालेख से लिंक करता है)

इन परियोजनाओं की भी जाँच करें:


18
+1 सिमेट्रिक्स साइट अब सक्रिय नहीं लगती है। हालाँकि, मुझे स्रोत पर कोड मिला: sourceforge.net/projects/simmetrics पॉइंटर के लिए धन्यवाद।
माइकल मर्चेंट

7
"आप इसे चेक कर सकते हैं" लिंक टूट गया है।
किरिल

1
इसलिए माइकल मर्चेंट ने ऊपर सही लिंक पोस्ट किया।
एमिल

2
Sourceforge पर सिमेट्रिक्स के लिए जार थोड़ा पुराना है, github.com/mpkorstanje/simmetrics
मावेन

@MichaelMerchant की टिप्पणी में जोड़ने के लिए, यह परियोजना जीथब पर भी उपलब्ध है । हालांकि बहुत सक्रिय नहीं है, लेकिन सोर्सफोर्ज की तुलना में हाल ही में थोड़ा अधिक है।
घुरदिल

163

0% -100% फैशन में दो तारों के बीच समानता की गणना करने का सामान्य तरीका , जैसा कि कई पुस्तकालयों में उपयोग किया जाता है, यह मापने के लिए है कि इसे कितना छोटा (% में) बदलना है ताकि आप इसे छोटी में बदल सकें।

/**
 * Calculates the similarity (a number within 0 and 1) between two strings.
 */
public static double similarity(String s1, String s2) {
  String longer = s1, shorter = s2;
  if (s1.length() < s2.length()) { // longer should always have greater length
    longer = s2; shorter = s1;
  }
  int longerLength = longer.length();
  if (longerLength == 0) { return 1.0; /* both strings are zero length */ }
  return (longerLength - editDistance(longer, shorter)) / (double) longerLength;
}
// you can use StringUtils.getLevenshteinDistance() as the editDistance() function
// full copy-paste working code is below


कम्प्यूटिंग editDistance():

editDistance()समारोह से ऊपर की गणना करने की उम्मीद है संपादित दूरी दो तार के बीच। इस चरण के लिए कई कार्यान्वयन हैं , प्रत्येक विशिष्ट परिदृश्य को बेहतर ढंग से प्रस्तुत कर सकते हैं। सबसे आम लेवेंसाइटिन दूरी एल्गोरिथ्म है और हम इसे नीचे दिए गए हमारे उदाहरण में उपयोग करेंगे (बहुत बड़े तारों के लिए, अन्य एल्गोरिदम बेहतर प्रदर्शन करने की संभावना है)।

संपादित दूरी की गणना करने के लिए यहां दो विकल्प हैं:

  • आप Apache Commons Text के Levenshtein दूरी के कार्यान्वयन का उपयोग कर सकते हैं : apply(CharSequence left, CharSequence rightt)
  • इसे अपने में लागू करें। नीचे आपको एक उदाहरण कार्यान्वयन मिलेगा।


काम करने का उदाहरण:

ऑनलाइन डेमो यहाँ देखें।

public class StringSimilarity {

  /**
   * Calculates the similarity (a number within 0 and 1) between two strings.
   */
  public static double similarity(String s1, String s2) {
    String longer = s1, shorter = s2;
    if (s1.length() < s2.length()) { // longer should always have greater length
      longer = s2; shorter = s1;
    }
    int longerLength = longer.length();
    if (longerLength == 0) { return 1.0; /* both strings are zero length */ }
    /* // If you have Apache Commons Text, you can use it to calculate the edit distance:
    LevenshteinDistance levenshteinDistance = new LevenshteinDistance();
    return (longerLength - levenshteinDistance.apply(longer, shorter)) / (double) longerLength; */
    return (longerLength - editDistance(longer, shorter)) / (double) longerLength;

  }

  // Example implementation of the Levenshtein Edit Distance
  // See http://rosettacode.org/wiki/Levenshtein_distance#Java
  public static int editDistance(String s1, String s2) {
    s1 = s1.toLowerCase();
    s2 = s2.toLowerCase();

    int[] costs = new int[s2.length() + 1];
    for (int i = 0; i <= s1.length(); i++) {
      int lastValue = i;
      for (int j = 0; j <= s2.length(); j++) {
        if (i == 0)
          costs[j] = j;
        else {
          if (j > 0) {
            int newValue = costs[j - 1];
            if (s1.charAt(i - 1) != s2.charAt(j - 1))
              newValue = Math.min(Math.min(newValue, lastValue),
                  costs[j]) + 1;
            costs[j - 1] = lastValue;
            lastValue = newValue;
          }
        }
      }
      if (i > 0)
        costs[s2.length()] = lastValue;
    }
    return costs[s2.length()];
  }

  public static void printSimilarity(String s, String t) {
    System.out.println(String.format(
      "%.3f is the similarity between \"%s\" and \"%s\"", similarity(s, t), s, t));
  }

  public static void main(String[] args) {
    printSimilarity("", "");
    printSimilarity("1234567890", "1");
    printSimilarity("1234567890", "123");
    printSimilarity("1234567890", "1234567");
    printSimilarity("1234567890", "1234567890");
    printSimilarity("1234567890", "1234567980");
    printSimilarity("47/2010", "472010");
    printSimilarity("47/2010", "472011");
    printSimilarity("47/2010", "AB.CDEF");
    printSimilarity("47/2010", "4B.CDEFG");
    printSimilarity("47/2010", "AB.CDEFG");
    printSimilarity("The quick fox jumped", "The fox jumped");
    printSimilarity("The quick fox jumped", "The fox");
    printSimilarity("kitten", "sitting");
  }

}

आउटपुट:

1.000 is the similarity between "" and ""
0.100 is the similarity between "1234567890" and "1"
0.300 is the similarity between "1234567890" and "123"
0.700 is the similarity between "1234567890" and "1234567"
1.000 is the similarity between "1234567890" and "1234567890"
0.800 is the similarity between "1234567890" and "1234567980"
0.857 is the similarity between "47/2010" and "472010"
0.714 is the similarity between "47/2010" and "472011"
0.000 is the similarity between "47/2010" and "AB.CDEF"
0.125 is the similarity between "47/2010" and "4B.CDEFG"
0.000 is the similarity between "47/2010" and "AB.CDEFG"
0.700 is the similarity between "The quick fox jumped" and "The fox jumped"
0.350 is the similarity between "The quick fox jumped" and "The fox"
0.571 is the similarity between "kitten" and "sitting"

11
लेवेंसाइटिन दूरी विधि में उपलब्ध है org.apache.commons.lang3.StringUtils
क्लीनकॉड

@Cleankod अब यह कॉमन्स-टेक्स्ट का हिस्सा है: commons.apache.org/proper/commons-text/javadocs/api-release/org/…
Luiz

15

मैंने जावास्क्रिप्ट में Levenshtein दूरी एल्गोरिथ्म का अनुवाद किया :

String.prototype.LevenshteinDistance = function (s2) {
    var array = new Array(this.length + 1);
    for (var i = 0; i < this.length + 1; i++)
        array[i] = new Array(s2.length + 1);

    for (var i = 0; i < this.length + 1; i++)
        array[i][0] = i;
    for (var j = 0; j < s2.length + 1; j++)
        array[0][j] = j;

    for (var i = 1; i < this.length + 1; i++) {
        for (var j = 1; j < s2.length + 1; j++) {
            if (this[i - 1] == s2[j - 1]) array[i][j] = array[i - 1][j - 1];
            else {
                array[i][j] = Math.min(array[i][j - 1] + 1, array[i - 1][j] + 1);
                array[i][j] = Math.min(array[i][j], array[i - 1][j - 1] + 1);
            }
        }
    }
    return array[this.length][s2.length];
};

11

आप दो तारों के बीच के अंतर की गणना करने के लिए लेवेंसहाइट दूरी का उपयोग कर सकते हैं। http://en.wikipedia.org/wiki/Levenshtein_distance


2
लेवेंसाइटिन कुछ तारों के लिए महान है, लेकिन बड़ी संख्या में तारों के बीच तुलना करने का पैमाना नहीं होगा।
स्पैन

मैंने कुछ सफलता के साथ Java में Levenshtein का उपयोग किया है। मैंने बड़ी सूचियों पर तुलना की है, ताकि प्रदर्शन में बाधा उत्पन्न हो। यह भी थोड़ा सरल है और छोटे शब्दों (जैसे 3 या 4 वर्णों) के लिए दहलीज को ऊपर उठाने के लिए कुछ ट्विकिंग का उपयोग कर सकते हैं, जो देखने में अधिक से अधिक समान होना चाहिए (यह बिल्ली से कुत्ते के लिए केवल 3 संपादन है) पर ध्यान दें कि एडिट डिस्टेंस नीचे सुझाव दिया गया है कि बहुत ही समान हैं - लेवेंसहाइट संपादित दूरी का एक विशेष कार्यान्वयन है।
Rhubarb

यहां एक लेख दिखाया गया है कि एक कुशल एसक्यूएल क्वेरी के साथ लेवेंसहाइट को कैसे संयोजित करें: literatejava.com/sql/fuzzy-string-search-sql
थॉमस W

10

वहाँ वास्तव में वहाँ स्ट्रिंग समानता के बहुत सारे उपाय हैं:

  • लेवेंसहाइट दूरी संपादित करें;
  • दमेराऊ-लेवेंसहिन दूरी;
  • यारो-विंकलर समानता;
  • सबसे लंबे समय तक सामान्य अनुवर्ती दूरी संपादित करें;
  • क्यू-ग्राम (उकोनेन);
  • n- ग्राम दूरी (कोंद्रक);
  • जैकार्ड सूचकांक;
  • सोरेंसन-पासा गुणांक;
  • कोसाइन समानता;
  • ...

आप यहाँ इनका स्पष्टीकरण और जावा कार्यान्वयन पा सकते हैं: https://github.com/tdebatty/java-string-simularity


8

आप इसे अपाचे कॉमन्स जावा लाइब्रेरी का उपयोग करके प्राप्त कर सकते हैं । इसके भीतर इन दो कार्यों पर एक नज़र डालें:
- getLevenshteinDistance
- getFuzzyDistance


3
अक्टूबर 2017 तक, लिंक किए गए तरीकों को हटा दिया गया है। वर्गों का प्रयोग करें LevenshteinDistance और FuzzyScore से कॉमन्स पाठ पुस्तकालय के बजाय
vatbub



3

एक साहित्यिक खोजक की तरह मुझे लगता है अगर आपकी स्ट्रिंग एक दस्तावेज़ में बदल जाती है। शायद उस शब्द के साथ खोज करने से कुछ अच्छा हो जाएगा।

"प्रोग्रामिंग कलेक्टिव इंटेलिजेंस" में यह निर्धारित करने पर एक अध्याय है कि क्या दो दस्तावेज समान हैं। कोड पायथन में है, लेकिन यह साफ और पोर्ट करने में आसान है।


3

पहले उत्तर देने वाले के लिए धन्यवाद, मुझे लगता है कि ComputeEditDistance (s1, s2) की 2 गणनाएं हैं। इसे अधिक समय देने के कारण, कोड के प्रदर्शन में सुधार करने का निर्णय लिया। इसलिए:

public class LevenshteinDistance {

public static int computeEditDistance(String s1, String s2) {
    s1 = s1.toLowerCase();
    s2 = s2.toLowerCase();

    int[] costs = new int[s2.length() + 1];
    for (int i = 0; i <= s1.length(); i++) {
        int lastValue = i;
        for (int j = 0; j <= s2.length(); j++) {
            if (i == 0) {
                costs[j] = j;
            } else {
                if (j > 0) {
                    int newValue = costs[j - 1];
                    if (s1.charAt(i - 1) != s2.charAt(j - 1)) {
                        newValue = Math.min(Math.min(newValue, lastValue),
                                costs[j]) + 1;
                    }
                    costs[j - 1] = lastValue;
                    lastValue = newValue;
                }
            }
        }
        if (i > 0) {
            costs[s2.length()] = lastValue;
        }
    }
    return costs[s2.length()];
}

public static void printDistance(String s1, String s2) {
    double similarityOfStrings = 0.0;
    int editDistance = 0;
    if (s1.length() < s2.length()) { // s1 should always be bigger
        String swap = s1;
        s1 = s2;
        s2 = swap;
    }
    int bigLen = s1.length();
    editDistance = computeEditDistance(s1, s2);
    if (bigLen == 0) {
        similarityOfStrings = 1.0; /* both strings are zero length */
    } else {
        similarityOfStrings = (bigLen - editDistance) / (double) bigLen;
    }
    //////////////////////////
    //System.out.println(s1 + "-->" + s2 + ": " +
      //      editDistance + " (" + similarityOfStrings + ")");
    System.out.println(editDistance + " (" + similarityOfStrings + ")");
}

public static void main(String[] args) {
    printDistance("", "");
    printDistance("1234567890", "1");
    printDistance("1234567890", "12");
    printDistance("1234567890", "123");
    printDistance("1234567890", "1234");
    printDistance("1234567890", "12345");
    printDistance("1234567890", "123456");
    printDistance("1234567890", "1234567");
    printDistance("1234567890", "12345678");
    printDistance("1234567890", "123456789");
    printDistance("1234567890", "1234567890");
    printDistance("1234567890", "1234567980");

    printDistance("47/2010", "472010");
    printDistance("47/2010", "472011");

    printDistance("47/2010", "AB.CDEF");
    printDistance("47/2010", "4B.CDEFG");
    printDistance("47/2010", "AB.CDEFG");

    printDistance("The quick fox jumped", "The fox jumped");
    printDistance("The quick fox jumped", "The fox");
    printDistance("The quick fox jumped",
            "The quick fox jumped off the balcany");
    printDistance("kitten", "sitting");
    printDistance("rosettacode", "raisethysword");
    printDistance(new StringBuilder("rosettacode").reverse().toString(),
            new StringBuilder("raisethysword").reverse().toString());
    for (int i = 1; i < args.length; i += 2) {
        printDistance(args[i - 1], args[i]);
    }


 }
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.