web-dev-qa-db-fra.com

Trouver la différence entre deux chaînes

Supposons que j'ai deux longues chaînes. Ils sont presque identiques.

String a = "this is a example"
String b = "this is a examp"

Le code ci-dessus est juste par exemple. Les chaînes réelles sont assez longues.

Le problème est qu'une chaîne a 2 caractères de plus que l'autre.

Comment puis-je vérifier quels sont ces deux caractères?

20
user17526

Vous pouvez utiliser StringUtils.difference (String first, String second) .

Voici comment ils l'ont mis en œuvre:

public static String difference(String str1, String str2) {
    if (str1 == null) {
        return str2;
    }
    if (str2 == null) {
        return str1;
    }
    int at = indexOfDifference(str1, str2);
    if (at == INDEX_NOT_FOUND) {
        return EMPTY;
    }
    return str2.substring(at);
}

public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
    if (cs1 == cs2) {
        return INDEX_NOT_FOUND;
    }
    if (cs1 == null || cs2 == null) {
        return 0;
    }
    int i;
    for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
        if (cs1.charAt(i) != cs2.charAt(i)) {
            break;
        }
    }
    if (i < cs2.length() || i < cs1.length()) {
        return i;
    }
    return INDEX_NOT_FOUND;
}
26
JRL

Pour trouver la différence entre 2 chaînes, vous pouvez utiliser la classe StringUtils et la classe différence = méthode. Il compare les deux chaînes et renvoie la partie où elles diffèrent.

 StringUtils.difference(null, null) = null
 StringUtils.difference("", "") = ""
 StringUtils.difference("", "abc") = "abc"
 StringUtils.difference("abc", "") = ""
 StringUtils.difference("abc", "abc") = ""
 StringUtils.difference("ab", "abxyz") = "xyz"
 StringUtils.difference("abcde", "abxyz") = "xyz"
 StringUtils.difference("abcde", "xyz") = "xyz"

Voir: https://commons.Apache.org/proper/commons-lang/javadocs/api-2.6/org/Apache/commons/lang/StringUtils.html

13
ccu

Sans parcourir les chaînes, vous ne pouvez savoir que que elles sont différentes, pas - et cela uniquement si elles sont de longueur différente. Si vous avez vraiment besoin de savoir quels sont les différents caractères, vous devez parcourir les deux chaînes en tandem et comparer les caractères aux endroits correspondants.

13
Kilian Foth

L'extrait suivant Java Java calcule efficacement un ensemble minimal de caractères qui doivent être supprimés (ou ajoutés à) les chaînes respectives afin de rendre les chaînes égales. C'est un exemple de programmation dynamique.

import Java.util.HashMap;
import Java.util.Map;

public class StringUtils {

    /**
     * Examples
     */
    public static void main(String[] args) {
        System.out.println(diff("this is a example", "this is a examp")); // prints (le,)
        System.out.println(diff("Honda", "Hyundai")); // prints (o,yui)
        System.out.println(diff("Toyota", "Coyote")); // prints (Ta,Ce)
        System.out.println(diff("Flomax", "Volmax")); // prints (Fo,Vo)
    }

    /**
     * Returns a minimal set of characters that have to be removed from (or added to) the respective
     * strings to make the strings equal.
     */
    public static Pair<String> diff(String a, String b) {
        return diffHelper(a, b, new HashMap<>());
    }

    /**
     * Recursively compute a minimal set of characters while remembering already computed substrings.
     * Runs in O(n^2).
     */
    private static Pair<String> diffHelper(String a, String b, Map<Long, Pair<String>> lookup) {
        long key = ((long) a.length()) << 32 | b.length();
        if (!lookup.containsKey(key)) {
            Pair<String> value;
            if (a.isEmpty() || b.isEmpty()) {
                value = new Pair<>(a, b);
            } else if (a.charAt(0) == b.charAt(0)) {
                value = diffHelper(a.substring(1), b.substring(1), lookup);
            } else {
                Pair<String> aa = diffHelper(a.substring(1), b, lookup);
                Pair<String> bb = diffHelper(a, b.substring(1), lookup);
                if (aa.first.length() + aa.second.length() < bb.first.length() + bb.second.length()) {
                    value = new Pair<>(a.charAt(0) + aa.first, aa.second);
                } else {
                    value = new Pair<>(bb.first, b.charAt(0) + bb.second);
                }
            }
            lookup.put(key, value);
        }
        return lookup.get(key);
    }

    public static class Pair<T> {
        public Pair(T first, T second) {
            this.first = first;
            this.second = second;
        }

        public final T first, second;

        public String toString() {
            return "(" + first + "," + second + ")";
        }
    }
}
7
jjoller
String strDiffChop(String s1, String s2) {
    if (s1.length > s2.length) {
        return s1.substring(s2.length - 1);
    } else if (s2.length > s1.length) {
        return s2.substring(s1.length - 1);
    } else {
        return null;
    }
}
2
GlenPeterson

Pour trouver les mots différents dans les deux lignes, on peut utiliser le code suivant.

    String[] strList1 = str1.split(" ");
    String[] strList2 = str2.split(" ");

    List<String> list1 = Arrays.asList(strList1);
    List<String> list2 = Arrays.asList(strList2);

    // Prepare a union
    List<String> union = new ArrayList<>(list1);
    union.addAll(list2);

    // Prepare an intersection
    List<String> intersection = new ArrayList<>(list1);
    intersection.retainAll(list2);

    // Subtract the intersection from the union
    union.removeAll(intersection);

    for (String s : union) {
        System.out.println(s);
    }

À la fin, vous aurez une liste de mots différents dans les deux listes. On peut le modifier facilement pour avoir simplement les différents mots dans la première liste ou la deuxième liste et non simultanément. Cela peut être fait en supprimant l'intersection uniquement de list1 ou list2 au lieu de l'union.

Le calcul de l'emplacement exact peut être effectué en additionnant les longueurs de chaque mot dans la liste de fractionnement (avec la regex de fractionnement) ou en faisant simplement String.indexOf ("subStr").

1
stolen_leaves

Pour obtenir directement uniquement la section modifiée, et pas seulement la fin, vous pouvez utiliser le patch de correspondance Diff de Google .

List<Diff> diffs = new DiffMatchPatch().diffMain("stringend", "stringdiffend");
  for (Diff diff : diffs) {
    if (diff.operation == Operation.INSERT) {
      return diff.text; // Return only single diff, can also find multiple based on use case
    }
  }
}

Pour ajouter dans Android: implementation 'org.bitbucket.cowwoc:diff-match-patch:1.2'

Ce package est beaucoup plus puissant que cette fonctionnalité, il est principalement utilisé pour créer des outils liés aux différences.

0
Gibolt