Equal() и equalsIgnoreCase() возвращает false для равных строк

Я работаю с eclipse IDE (версия: 3.4.2) на Mac, и я встретил следующую проблему.

При сравнении строк, использующих методы equal() или equalsIgnoreCase(), я получаю false, даже если строка равна. Например, приведенный ниже код рассматривает следующее условие как false, даже если значения [0] = "debug_mode"

if (values[0].equalsIgnoreCase("debug_mode")) 
    debug_mode = true;

который является частью следующего цикла:

String value = dis.readLine();
String values[] = value.trim().split("=");
if (values.length >= 2)
{
    Config.prnt_dbg_msg(values[0] + "\t" + values[1]);
    if (values[0].equalsIgnoreCase("debug_mode")) 
        debug_mode = isTrue(values[1]);
    if (values[0].equalsIgnoreCase("debug_query_parsing")) 
        debug_query_parsing = isTrue(values[1]);
    if (values[0].equalsIgnoreCase("username")) 
        Connection_Manager.alterAccessParameters(values[1], null, null);
    if (values[0].equalsIgnoreCase("password")) 
        Connection_Manager.alterAccessParameters(null, values[1], null);
if (values[0].equalsIgnoreCase("database")) 
        Connection_Manager.alterAccessParameters(null, null, values[1]);
    if (values[0].equalsIgnoreCase("allow_duplicate_entries")) 
        allow_duplicate_entries = isTrue(values[1]);
}                         

Я попытался использовать value[0].equal("debug_mode") и получил тот же результат. Кто-нибудь знает, почему?

Ответ 1

Это было бы очень странно:) Можете ли вы изменить приведенный выше код на это:

if ("debug_mode".equalsIgnoreCase("debug_mode")) 
    debug_mode = true;

подтвердите, что он работает нормально, а затем дважды проверьте, почему ваш values[0] не является "debug_mode".

Вот что приходит мне в голову сейчас, как список вещей, которые нужно проверить:

  • Убедитесь, что values[0].length() == "debug_mode".length()
  • Я очень сомневаюсь, но позвольте мне поместить его на стол в любом случае - вы случайно используете Unicode?
  • Вы можете напечатать каждый символ и сделать .equals() между этим символом и соответствующим символом строки "debug_mode"?
  • Если это в более крупном проекте, можете ли вы сделать то же самое в простом Java-проекте и подтвердить, что он там работает?

Чтобы прояснить проблему, на самом деле проблема заключается в использовании DataInputStream.readLine. Из javadoc (http://download.oracle.com/javase/1.6.0/docs/api/java/io/DataInputStream.html):

readLine()
      Deprecated. This method does not properly convert bytes to characters. ...

На самом деле это имеет отношение к Unicode тонким образом - когда вы делаете writeChar, вы фактически пишете два байта 0 и 97, юникод большого конца для буквы a.

Здесь содержится автономный фрагмент, который показывает поведение:

import java.io.*;
import java.util.*;

public class B {
  public static void main(String[] args) throws Exception {
    String os = "abc";

    System.out.println("---- unicode, big-endian");
    for(byte b: os.getBytes("UTF-16BE")) {
      System.out.println(b);
    }

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);

    for(char c: os.toCharArray()) {
      dos.writeChar(c);
    }

    byte[] ba = baos.toByteArray();

    System.out.println("---- ba");
    for(byte b: ba) {
      System.out.println(b);
    }

    ByteArrayInputStream bais = new ByteArrayInputStream(ba);
    DataInputStream dis = new DataInputStream(bais);

    System.out.println("---- dis");
    String s = dis.readLine();
    System.out.println(s);
    System.out.println("String length is " + s.length() 
      + ", but you would expect " + os.length() 
      + ", as that is what you see printed...");
  }
}

Мораль истории - не используйте устаревшие api... Кроме того, пробел - это молчащий убийца: http://www.codinghorror.com/blog/2009/11/whitespace-the-silent-killer.html

Ответ 2

У меня только что была такая же проблема, используя equalsIgnoreCase.

После нескольких часов просмотра на экране, отлаживая код, который меня понял, что у моего оператора if есть; в конце,

то есть.

if ("stupid".equalsIgnoreCase.("STupid");
{
     //it always gets here 

}

Надеюсь, что это поможет кому-то в будущем.

Ответ 3

Я с другими, это сумасшествие, и этого не должно быть. Я согласен с тем, что распечатка может помочь, но я собираюсь предположить, что вы это пробовали.

Возможно ли это проблема локализации? То есть, когда вы вводите debug_mode в редакторе (для строки), это строка "debug_mode", но когда вы вводите строку во время выполнения, терминал настроен на использование другого языка, и вы получаете другое (но идентичный вид)?

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

String value = dis.readLine();
String values[] = value.trim().split("=");

System.out.println("Input:");

for (int i = 0; i < values[0].length(); i++) {
    System.out.print((int) values[0].charAt(i));
    System.out.print(' ');
}

System.out.println("Hardcoded:");

String debugMode = "debug_mode";

for (int i = 0; i < debugMode.length(); i++) {
    System.out.print((int) debugMode.charAt(i));
    System.out.print(' ');
}

Теперь для этого вам нужно будет ввести код (или, по крайней мере, константу debug_mode), чтобы он имел тот же набор символов, что и вы.

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

Ответ 4

Попробуйте compareToIgnoreCase:

if (values[0].compareToIgnoreCase("debug_mode") != 0) 
    debug_mode = true;

И если это не сработает, попробуйте compareTo.

И если это не сработает, попробуйте:

String d = (String)values[0];
if (d.compareToIgnoreCase("debug_mode") != 0) 
        debug_mode = true;

И если они не работают, у вас серьезная проблема с Java. Либо он древний, либо вам не нравится.

Ответ 5

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

У меня было две разные строки: строка A и строка B, поступающая из разных источников, они казались мне идентичными, но я получал не равный для них метод equals

даже при использовании equalsIgnoreCase дал мне false

Я был невежественным, потому что, когда я печатал эти строки (A и B), чтобы проверить, как они выглядят, они были

String A is dsycuii343qzx899+ty=
String B is dsycuii343qzx899+ty=

Итак, Затем я проверил длину двух строк, которые дали мне ключ

String A length = 20
String B length = 21

SO, что означает, что я могу что-то упустить,

так что я сделал

Я проверил каждую строку char на char, и я узнал о проблеме

Строка A, которая выглядела как dsycuii343qzx899+ty=, была фактически dsycuii343qzx899+ty=\n

В конце был символ LF (новый символ строки), который был замечен во время проверки журнала

надеюсь, что это может помочь кому-то.

Ответ 6

Проверить, дважды проверить и перепроверять. Очевидно, что описанная вами ситуация невозможна.

Ответ 7

Вы можете легко запустить это на Android с помощью SpannableString, , например, когда TextView имеет автоматическую активацию, например:

// Outputs "a string"
Log.d("test", "TextView text: " + textView.getText());

// Outputs "a string"
Log.d("test", "Text to match: " + "a string");

if( textView.getText().equals("a string") )
{
    // Won't get here
}

Вы можете выполнить быстрый тест, чтобы увидеть, какую строку textView.getText() возвращает:

Log.d("test", "String class: " + textView.getText().getClass().getSimpleName());

Если у вас есть SpannableString, вам просто нужно вызвать toString() на нем для выполнения условия if:

if( textView.getText().toString().equals("a string") )
{
    // We're here
}

Ответ 8

В другой заметке у меня была страница JSP с аналогичными проблемами при сравнении полученного "состояния" таблицы:

try{



  // ID is a Primary Key (unique). STATUS column data type in DB: CHAR(20)
  rs = stmt.executeQuery("select STATUS from TEMP_TABLE WHERE ID='"+id+"'");

  while(rs.next()){

        status = (String) rs.getString("STATUS");

  }
   if ( status.equalsIgnoreCase("active") )
   {
          // Run some DB Queries
   } else {
           out.write("Page can't be accessed due to status : " + status);
   }
} catch(Exception e) { e.getMessage(); }
finally {
         //close all open objects
}

По неизвестным мне причинам он всегда попадает в блок else с сообщением "Страница не может быть доступна из-за статуса: активно", хотя статус "активен". Я попытался закрыть объекты rs и stmt после каждого запроса до и после запуска этого запроса, но это не помогло. В конце концов я изменил свой запрос на

"select STATUS from TEMP_TABLE WHERE ID='"+id+"' where STATUS='ACTIVE'"

Ответ 9

Я думаю, проблема может заключаться в том, что хотя фактические значения String равны, их базовый byte[] может и не быть.

Попробуйте использовать этот метод для сравнения двух byte[]:

private String printBytes(String str) {
    byte[] bytes = str.getBytes(ENCODING);
    String output = "byte[";
    for (int i = 0; i < bytes.length; i++) {
        output += Byte.toString(bytes[i]);
        if (i < bytes.length - 1) {
            output += ", ";
        }
    }
    output += "]";
    return output;
}

Например:

Charset ENCODING = Charset.forName("UTF-8");
Log.d(LOG_TAG, "string1: \"" + string1 + "\" - " + printBytes(string1));
Log.d(LOG_TAG, "string2: \"" + string2 + "\" - " + printBytes(string2));

Это позволит визуальное сравнение. Для длинных String s вы можете сравнить программный код byte[] путем одновременного итерации по обеим массивам и сравнения значений.

Ответ 10

В моем случае я только что обнаружил, что одна строка имела место перед строкой. Мои строки были похожи на "УСПЕХ" и "УСПЕХ", поэтому он возвращал false. Я использовал:

 String st1=st.replaceAll("\\s","");

и, следовательно, проблема решена.

Ответ 11

Может быть, мой ответ очень позже, но он будет кому-то полезен.

Просто обрезать() обе строки перед сравнением

       eg: if(data1.trim().equalsIgnoreCase(data2.trim()))
            {
                //This gives proper result
            }

Ответ 12

Может быть пометка порядка байтов: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8

просто попробуйте str1.length() и str2.length(), и, если это не одно и то же, выполните str1.charAt(0) и y =, если вы получите что-то вроде '\ uFEFF' 65279, чем это ваша проблема