equal() and equalsIgnoreCase() return false for equal strings
I'm working with eclipse IDE (Version: 3.4.2) on a mac and I have met the following issue.
When comparing between strings using equal() or equalsIgnoreCase() methods I receive false even when the string are equal. For example, the code below consider the following condition as false, even when values[0] = "debug_mode"
if (values[0].equalsIgnoreCase("debug_mode"))
debug_mode = true;
which is part of the following loop:
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(val开发者_StackOverflowues[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]);
}
I tried to use value[0].equal("debug_mode")
and got the same result.
Does someone have any idea why?
That would be very strange indeed :) Can you change the above code to this:
if ("debug_mode".equalsIgnoreCase("debug_mode"))
debug_mode = true;
confirm it works fine and then double check why your values[0]
is not "debug_mode".
Here's what comes to my mind right now as a list of things to check:
- Check that
values[0].length() == "debug_mode".length()
- I highly doubt, but let me put it on the table anyway - are you by any chance using Unicode?
- Can you print each character and do
.equals()
between that character and the respective character of the "debug_mode" string? - If this is in a bigger project, can you do the same in a simple Java project and confirm it works there?
To clarify, the problem is actually using DataInputStream.readLine
. From 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. ...
It actually has to do with Unicode in a subtle way - when you do writeChar
you actually write two bytes 0
and 97
, big-endian Unicode for the letter a
.
Here's a self-contained snippet that shows the behavior:
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...");
}
}
Moral of the story - don't use deprecated api... Also, whitespace is the silent killer: http://www.codinghorror.com/blog/2009/11/whitespace-the-silent-killer.html
I have just had this exact same issue, using equalsIgnoreCase.
After hours of staring at the screen, debugging the code it dawned on me that my if statement had a ; at the end,
i.e.
if ("stupid".equalsIgnoreCase.("STupid");
{
//it always gets here
}
Hope this helps someone in future.
I'm with the others, this is crazy and shouldn't happen. I agree that printing it out may help, but I'm going to assume you've tried that.
Is it possible it's a localization issue? That is, when you type in debug_mode in the editor (for the string) it's the string "debug_mode", but when you type the string in during execution the terminal is set to use a different language and you're getting a different (but identical looking) character?
To find out, loop through the string you get in and print out each character's integer value, and then do the same with your string that's hardcoded and see if they are the same.
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(' ');
}
Now for this to work, you'd have to type the code (or at least the debug_mode constant) so it has the same character set as you are using.
I'd be willing to bet a good sum of money this isn't the issue, but even if it isn't it should prove instructive and show you what is different.
Try compareToIgnoreCase
:
if (values[0].compareToIgnoreCase("debug_mode") != 0)
debug_mode = true;
And if that doesn't work, try compareTo
instead.
And if that doesn't work, try:
String d = (String)values[0];
if (d.compareToIgnoreCase("debug_mode") != 0)
debug_mode = true;
And if those don't work, you have a serious Java issue. Either it's ancient or it doesn't like you.
Although there are few very good and correct answers above I would still like to mention my personal experience so that anyone facing same problem could get instant help from this answer.
I had two different string say string A and string B coming from diffrent sources, they seemed identical to me but I was getting not equal for them on using equals method
even on using equalsIgnoreCase gave me false
I was clueless because when I was printing those string (A & B) to check what they look like they were
String A is dsycuii343qzx899+ty=
String B is dsycuii343qzx899+ty=
so, I then checked length of the two string which gave me the clue
String A length = 20
String B length = 21
SO that means I might be missing something,
so what I did was
I checked each String char by char and I got to know the problem
String A which seemed like dsycuii343qzx899+ty=
was actually dsycuii343qzx899+ty=\n
i.e there was a LF
(new line character) at the end which was noticed while Log check
hope it might help someone.
You can easily run into this on Android with SpannableString
, like when a TextView has autolinking enabled, for instance:
// 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
}
You can do a quick test to see what kind of string textView.getText() returns by doing:
Log.d("test", "String class: " + textView.getText().getClass().getSimpleName());
If indeed you've got a SpannableString
, you simply need to call toString() on it for the if condition to be satisfied:
if( textView.getText().toString().equals("a string") )
{
// We're here
}
On a different note, I had a JSP page having similar problems while comparing the retrieved "status" of a table:
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
}
For reasons unknown to me it always hits the else block with message "Page can't be accessed due to status : active", though status is "active". I tried closing rs and stmt objects after each query before and after running this Query but that didn't helped. Eventually I changed my Query to
"select STATUS from TEMP_TABLE WHERE ID='"+id+"' where STATUS='ACTIVE'"
I think the problem may be that although the actual String
values are equal, their underlying byte[]
's may not be.
Try using this method to compare the two byte[]
's:
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;
}
For example:
Charset ENCODING = Charset.forName("UTF-8");
Log.d(LOG_TAG, "string1: \"" + string1 + "\" - " + printBytes(string1));
Log.d(LOG_TAG, "string2: \"" + string2 + "\" - " + printBytes(string2));
This would enable a visual comparison. For long String
s, you could compare the byte[]
's programmatically by iterating through both arrays at the same time and comparing the values.
In my case I just discovered one string had space before the string.
My strings were like " SUCCESS" and "SUCCESS",
so it was returning false
. I used:
String st1=st.replaceAll("\\s","");
and thus problem solved.
May be my answer is very later but it will be useful to someone.
Just trim() both the strings before comparison
eg: if(data1.trim().equalsIgnoreCase(data2.trim()))
{
//This gives proper result
}
Can be byte order mark: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8
just try str1.length() and str2.length() and if it is not the same do str1.charAt(0) and y=if you get something like '\uFEFF' 65279 than that is your issue
精彩评论