Странное сравнение строк Java - PullRequest
2 голосов
/ 15 октября 2011

У меня небольшая проблема со сравнениями строк Java.

Я написал класс, который принимает строку и анализирует ее в произвольный тип дерева. Я написал класс toString, который затем снова преобразует это дерево в строку. В рамках своих модульных тестов я просто проверяю, что строка, сгенерированная методом toString, совпадает со строкой, которая была проанализирована в первую очередь.

Вот мой простой тест с несколькими распечатками, чтобы мы могли видеть, что происходит.

final String exp1 = "(a|b)";
final String exp2 = "((a|b)|c)";
final Node tree1 = Reader.parseExpression2(exp1);
final Node tree2 = Reader.parseExpression2(exp2);
final String t1 = tree1.toString();
final String t2 = tree2.toString();

System.out.println(":" + exp1 + ":" + t1 + ":");
System.out.println(":" + exp2 + ":" + t2 + ":");

System.out.println(exp1.compareToIgnoreCase(t1));
System.out.println(exp2.compareToIgnoreCase(t2));

System.out.println(exp1.equals(t1));
System.out.println(exp2.equals(t2));

Имеет следующий вывод; (NB ":" - используются в качестве разделителей, поэтому я могу убедиться, что нет лишних пробелов)

:(a|b):(a|b):
:((a|b)|c):((a|b)|c):
-1
-1
false
false

Исходя из сравнения вручную строк exp1 и exp2 с t1 и t2 соответственно, они абсолютно одинаковы. Но по какой-то причине Java настаивает на том, что они разные.

Это не очевидная ошибка использования == вместо .equals(), но я озадачен тем, почему две, казалось бы, одинаковые строки различны. Любая помощь будет высоко ценится:)

Ответы [ 3 ]

3 голосов
/ 15 октября 2011

Есть ли в одной из ваших строк пустой символ? Они могут не отображаться при использовании System.out.println(...).

Например, рассмотрим этот класс:

public class StringComparison {
    public static void main(String[] args) {
        String s = "a|b";
        String t = "a|b\0";
        System.out.println(":" + s + ":" + t + ":");
        System.out.println(s.equals(t));
    }
}

Когда я запустил это в Linux, он дал мне следующий вывод:

:a|b:a|b:
false

(Я также запускал его в Windows, но нулевой символ отображался в виде пробела.)

2 голосов
/ 15 октября 2011

Ну, это конечно выглядит хорошо. Что бы я сделал, это перебрал бы обе строки, используя charAt, чтобы сравнить каждый отдельный символ с эквивалентом в другой строке. Надеюсь, это как минимум расскажет вам обидчика.

Также выведите все остальное, что вы можете узнать об обеих строках, например длину.

Возможно, один из персонажей выглядит одинаково, но может быть и другим двойником Юникода: -)

Вы также можете захватить этот вывод и сделать подробный двоичный дамп на нем, например загрузить его в gvim и использовать инструмент шестнадцатеричного преобразования, или выполнить od -xcb (если доступно) для захваченного вывода. Там может быть очевидная разница, когда вы переходите к бинарному уровню экзамена.

1 голос
/ 15 октября 2011

У меня есть несколько предложений

  • Скопируйте каждый вывод и вставьте его в Блокнот (или любой аналогичный редактор), затем скопируйте их снова и сделайте что-то подобное

    System.out.println ( "(а | б)" compareToIgnoreCase ( "(а | б)").);

  • Распечатайте целочисленное представление каждого символа. Если это странный юникод, представление int будет другим.

  • Кроме того, какую версию JDK вы используете?

...