字符串包含相同的字符但仍然不同

时间:2016-05-26 10:01:10

标签: java android string

我正在尝试读取.txt文件并将每个句子用作团队的名称,同时使用该名称来寻找另一个.txt文件以获取其内容。所有.txt文件都位于我的assets文件夹的根目录下。第一个.txt文件工作正常,我使用assetmanager.openreadLine()来获取字符串,但是当使用该字符串作为参数来获取第二个.txt时,我得到java.io.FileNotFoundException。但是,当使用硬编码字符串调用相同的.txt文件时,一切正常。经过进一步检查,我发现硬编码字符串和用作参数的字符串在使用equals()函数后返回false。

这是调用first.txt

的方法
private void loadTeams() {
    try {
        BufferedReader r = new BufferedReader(new InputStreamReader(assetManager.open("matches.txt")));
        String name, bio, trainer;
        for(int i = 0; i < 4; i++){
            name = r.readLine();
            bio = r.readLine();
            trainer = r.readLine();
            System.out.println(name+", "+bio+", "+trainer);
            teams[i] = new Team(name, bio, i, loadPlayers(name), trainer);
        }
        r.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

使用&#34; name&#34;作为以下方法的参数:

private Player[] loadPlayers(String teamName){
    Player[] players = new Player[11];

    try {
        String path = "team_Netherlands.txt";     //works
        String path2 = "team_"+teamName+".txt";     //doesn't work?
        System.out.println("are "+path+" and " +path2 +" the same? "+path.equals(path2));

        BufferedReader r = new BufferedReader(new InputStreamReader(assetManager.open(path2)));

        //perform operations on the obtained info
        r.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return players;
}

文件中的第一句是&#34;荷兰&#34; (没有报价) 我认为应该为 path2 变量导致team_Netherlands.txt。 然而,使用它会使应用程序崩溃。使用路径变量,它可以正常工作。 println确认字符串不相等。 (见logcat的第一句)

logcat的:

05-26 11:18:23.152 2960-2960/com.myname.testapp I/System.out: are team_Netherlands.txt and team_Netherlands.txt the same? false
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err: java.io.FileNotFoundException: team_Netherlands.txt
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.content.res.AssetManager.openAsset(Native Method)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:354)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:328)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at com.myname.testapp.Poule_Activity.load_Players(Poule_Activity.java:144)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at com.myname.testapp.Poule_Activity.load_Teams(Poule_Activity.java:94)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at com.myname.testapp.Poule_Activity.onCreate(Poule_Activity.java:53)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.app.Activity.performCreate(Activity.java:5990)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2332)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2442)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.app.ActivityThread.access$800(ActivityThread.java:156)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1351)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
05-26 11:18:23.152 2960-2960/com.myname.testapp W/System.err:     at android.os.Looper.loop(Looper.java:211)
05-26 11:18:23.153 2960-2960/com.myname.testapp W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5373)
05-26 11:18:23.153 2960-2960/com.myname.testapp W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
05-26 11:18:23.153 2960-2960/com.myname.testapp W/System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
05-26 11:18:23.153 2960-2960/com.myname.testapp W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
05-26 11:18:23.153 2960-2960/com.myname.testapp W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)    

为什么这些字符串不相同以及如何使它们相等? (即,使非硬编码字符串等于硬编码字符串)

6 个答案:

答案 0 :(得分:7)

如果我执行此代码:

public static void main(String[] args) {
    load_Players("Netherlands");
}

private static void load_Players(String team_Name) {
    String path = "team_Netherlands.txt"; // works
    String path2 = "team_" + team_Name + ".txt"; // doesn't work?
    System.out.println("are " + path + " and " + path2 + " the same? " + path.equals(path2));
}

一切都按预期工作,所以......出了什么问题?

正如您在日志中看到的那样,首先荷兰不是蓝色的,这意味着解析器找到了不同的东西。

enter image description here

可疑呃?

<强>检查:

当我将这部分代码粘贴到我的日食中时:

team_Netherlands.txt and team_Netherlands.txt 

保存时出现此错误:

enter image description here

如果我选择选项,请选择第一个字符:

System.out.println("team_Netherlands.txt".equals("team_Netherlands.txt"));
                                                       ↑ this one!!!

因此您可以使用此代码段检查错误的编码:

public static void main(String[] args) {
    String rightString = "_Netherlands.txt";
    String wrongString = "_Netherlands.txt";

    System.out.println("WRONG HASH");
    System.out.println(rightString.hashCode());
    System.out.println("\nRIGHT HASH");
    System.out.println(wrongString.hashCode());

    System.out.println("\nRIGHT");
    printChars(rightString);

    System.out.println("\n\nWRONG");
    printChars(wrongString);

}

private static void printChars(String s) {
    for (Character c : s.toCharArray()) {
        System.out.print((int) c + " ");
    }
}

<强>输出:

WRONG HASH
1109617587

RIGHT HASH
-428164238

RIGHT
95 78 101 116 104 101 114 108 97 110 100 115 46 116 120 116 

WRONG
95 65279 78 101 116 104 101 114 108 97 110 100 115 46 116 120 116 
// ↑ here!!

解决方案:(source

  • 使用Apache IO Commons的BOMInputStream
  • 手动处理(快速简便):

    private static String clean(String s) throws Exception {
        InputStream is = new ByteArrayInputStream(s.getBytes());
        try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
            // BOM marker will only appear on the very beginning
            br.mark(4);
            if ('\ufeff' != br.read())
                br.reset(); // not the BOM marker
    
            return br.readLine();
        }
    }
    

测试它!:

public static void main(String[] args) throws Exception {
    String rightString = "Netherlands.txt";
    String wrongString = "Netherlands.txt";

    System.out.println("\nCOMPARE");
    System.out.println(rightString.equals(wrongString));
    System.out.println("\nCLEAN COMPARE");
    System.out.println(clean(rightString).equals(clean(wrongString)));

    System.out.println("\nRIGHT");
    printChars(clean(rightString));

    System.out.println("\n\nWRONG");
    printChars(clean(wrongString));
}

private static String clean(String s) throws Exception {
    InputStream is = new ByteArrayInputStream(s.getBytes());
    try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
        // BOM marker will only appear on the very beginning
        br.mark(4);
        if ('\ufeff' != br.read())
            br.reset(); // not the BOM marker

        return br.readLine();
    }
}

private static void printChars(String s) {
    for (Character c : s.toCharArray()) {
        System.out.print((int) c + " ");
    }
}

输出:

COMPARE
false

CLEAN COMPARE
true

RIGHT
78 101 116 104 101 114 108 97 110 100 115 46 116 120 116 

WRONG
78 101 116 104 101 114 108 97 110 100 115 46 116 120 116 

答案 1 :(得分:5)

您从文件中读取的team_name前面包含UTF-8 byte order mark个八位字节

ef bb bf

并且它们在日志输出中不可见。

保存没有BOM的文件,或remove the BOM in your code.

答案 2 :(得分:1)

它必须有一些不可见的字符。

你能告诉我们package org.arpan.spring.mvc; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class HelloController { @RequestMapping(value="/hello") public String getMessage(ModelMap model) { model.addAttribute("message", "Hello this is my first spring project!"); return "Hello"; } @RequestMapping(value="/hey/{username}") public String getMessage(ModelMap model,@PathVariable String username) { System.out.println(username); model.addAttribute("message", "Hey this is my first spring project!"); return "Hello1"; } @RequestMapping(value="/hi/{id}") public String getMessage1( ModelMap model,@PathVariable("username2") String id) { model.addAttribute("message", "Hi this is my first spring project!"); return "Hello"; } } path.getBytes(),输出数组数据。

答案 3 :(得分:0)

您可以执行以下操作:

    String s1="abc    def";
    String s2="abc def";
    s1=s1.trim().replaceAll("\\s+", " ");
    System.out.println(s1.equals(s2));

显然,文本文件中的字符串看起来不错,但您仍然可以选择执行上述操作以确保等于!

答案 4 :(得分:0)

您可以找到问题的答案here。您要比较的字符串是不同的对象,这就是您得到错误的原因。您实际上并没有比较这些字符串包含的值。

答案 5 :(得分:0)

问题在于编码。 您从文本文件中读取的名称是UTF编码的。

你可以尝试做的是

String path3 = new String(path, "UTF-8");
String path4 = new String(path2, "UTF-8");

现在在path3和path4上进行字符串比较并检查。