30

假设我有两个长字符串。它们几乎相同。

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

上面的代码只是示例。实际的字符串很长。

问题是一个字符串比另一个字符串多2 个字符

我如何检查这两个字符是哪一个?

4

11 回答 11

36

您可以使用StringUtils.difference(String first, String second)

他们是这样实现的:

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;
}
于 2012-08-23T10:27:56.317 回答
19

要查找 2 个字符串之间的差异,您可以使用StringUtils类和差异方法。它比较两个字符串,并返回它们不同的部分。

 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"

请参阅:https ://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html

于 2015-04-29T19:30:13.573 回答
13

如果不遍历字符串,您只能知道它们是不同的,而不是在哪里- 并且只有它们的长度不同。如果你真的需要知道不同的字符是什么,你必须逐个遍历两个字符串并比较相应位置的字符。

于 2012-08-23T06:42:53.180 回答
13

下面的 Java 片段有效地计算了一组最小的字符,这些字符必须从相应的字符串中删除(或添加到)以使字符串相等。这是动态规划的一个例子。

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 + ")";
        }
    }
}
于 2018-10-10T15:27:31.630 回答
6

要直接获取更改的部分,而不仅仅是结尾,您可以使用 Google 的Diff Match Patch

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
  }
}

对于 Android,添加:implementation 'org.bitbucket.cowwoc:diff-match-patch:1.2'

这个包比这个功能强大得多,它主要用于创建diff相关的工具。

于 2019-07-31T02:55:34.053 回答
2
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;
    }
}
于 2012-08-23T11:55:31.820 回答
2

Google 的 Diff Match Patch 很好,但安装到我的 Java maven 项目中很痛苦。只是添加一个 Maven 依赖项是行不通的;eclipse 刚刚创建了目录并添加了 lastUpdated 信息文件。最后,在第三次尝试时,我在我的 pom 中添加了以下内容:

<dependency>
    <groupId>fun.mike</groupId>
     <artifactId>diff-match-patch</artifactId>
    <version>0.0.2</version>
</dependency>

然后我从https://search.maven.org/search?q=g:fun.mike%20AND%20a:diff-match-patch%20AND%20v手动将 jar 和源 jar 文件放入我的 .m2 存储库中: 0.0.2

毕竟,以下代码有效:

import fun.mike.dmp.Diff;
import fun.mike.dmp.DiffMatchPatch;

DiffMatchPatch dmp = new DiffMatchPatch();
LinkedList<Diff> diffs = dmp.diff_main("Hello World.", "Goodbye World.");
System.out.println(diffs);

结果:

[Diff(DELETE,"Hell"), Diff(INSERT,"G"), Diff(EQUAL,"o"), Diff(INSERT,"odbye"), Diff(EQUAL," World.")]

显然,这最初并不是编写(甚至完全移植)到 Java 中的。(diff_main?我能感觉到 C 燃烧到我的眼睛里 :-))仍然有效。对于使用长而复杂的字符串的人来说,它可能是一个有价值的工具。

于 2019-10-16T16:56:08.313 回答
1

要查找两行中不同的单词,可以使用以下代码。

    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);
    }

最后,您将获得两个列表中不同的单词列表。人们可以轻松地对其进行修改,以便在第一个列表或第二个列表中简单地使用不同的单词,而不是同时使用。这可以通过仅从 list1 或 list2 而不是并集中删除交集来完成。

可以通过将拆分列表中每个单词的长度相加(以及拆分正则表达式)或简单地执行 String.indexOf("subStr") 来计算确切位置。

于 2015-03-11T12:04:19.967 回答
0

另一个发现字符串之间差异的优秀库是https://github.com/java-diff-utils上的 DiffUtils 。我使用了 Dmitry Naumenko 的叉子:

public void testDiffChange() {
    final List<String> changeTestFrom = Arrays.asList("aaa", "bbb", "ccc");
    final List<String> changeTestTo = Arrays.asList("aaa", "zzz", "ccc");
    System.out.println("changeTestFrom=" + changeTestFrom);
    System.out.println("changeTestTo=" + changeTestTo);
    final Patch<String> patch0 = DiffUtils.diff(changeTestFrom, changeTestTo);
    System.out.println("patch=" + Arrays.toString(patch0.getDeltas().toArray()));

    String original = "abcdefghijk";
    String badCopy =  "abmdefghink";
    List<Character> originalList = original
            .chars() // Convert to an IntStream
            .mapToObj(i -> (char) i) // Convert int to char, which gets boxed to Character
            .collect(Collectors.toList()); // Collect in a List<Character>
    List<Character> badCopyList = badCopy.chars().mapToObj(i -> (char) i).collect(Collectors.toList());
    System.out.println("original=" + original);
    System.out.println("badCopy=" + badCopy);
    final Patch<Character> patch = DiffUtils.diff(originalList, badCopyList);
    System.out.println("patch=" + Arrays.toString(patch.getDeltas().toArray()));
}

结果准确显示了变化的地方(基于零的计数):

changeTestFrom=[aaa, bbb, ccc]
changeTestTo=[aaa, zzz, ccc]
patch=[[ChangeDelta, position: 1, lines: [bbb] to [zzz]]]
original=abcdefghijk
badCopy=abmdefghink
patch=[[ChangeDelta, position: 2, lines: [c] to [m]], [ChangeDelta, position: 9, lines: [j] to [n]]]
于 2019-10-16T16:39:03.187 回答
0

对于像这样的简单用例。您可以检查字符串的大小并使用拆分功能。对于你的例子

a.split(b)[1]
于 2022-03-03T19:03:10.437 回答
-1

你可以试试这个

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

String ans= a.replace(b, "");

System.out.print(now);      
//ans=le
于 2021-06-21T14:13:59.487 回答