【问题标题】:Strings contain the same characters but are still different [duplicate]字符串包含相同的字符但仍然不同[重复]
【发布时间】:2023-03-13 05:47:01
【问题描述】:

我正在尝试读取 .txt 文件并将每个句子用作团队的名称,同时使用该名称查找另一个 .txt 文件以获取其内容。所有 .txt 文件都在我的资产文件夹的根目录下。第一个.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();
    }
}

使用“名称”作为以下方法的参数:

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

文件中的第一句是“Netherlands”(不带引号) 我认为这应该导致 path2 变量的team_Netherlands.txt。 但是,使用它会使应用程序崩溃。使用 path 变量就可以了。 println 确认字符串不相等。 (见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)    

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

【问题讨论】:

  • 检查两个字符串长度
  • 感谢您的快速回复 :) 我认为您正在做一些事情:路径长度:20,路径 2 长度:16,您知道是什么原因造成的吗?
  • 试试path.trim().equals(path2.trim())
  • @Amit.rk3,仍然返回 false :(
  • "team_"+team_Name.trim()+".txt",我想这应该是我的第一条评论:)

标签: java android string


【解决方案1】:

如果我执行这段代码:

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

一切正常,所以...怎么了?


正如您在日志中看到的,第一个荷兰不是蓝色的,这意味着解析器发现了一些不同的东西。

可疑啊?


检查:

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

team_Netherlands.txt and team_Netherlands.txt 

保存时出现此错误:

如果我选择选项选择它选择的第一个字符:

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

所以你传递了错误的编码,你可以用这个 sn-p 检查:

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 

【讨论】:

  • 哦,我明白了,我认为这是有道理的,我会更改编码并让你知道它的结果:)
  • 不幸的是,将所有内容都更改为 UTF-8 并没有帮助,需要什么正确的编码?
  • 请检查我的更新。
  • 哦抱歉我没看到,谢谢你的更新!
  • 不客气。我还发布了带有工作代码和解决方案的最新更新,您发现了一个有趣的错误,我想了解更多信息......但我同意接受的答案是@laalto one,我在他的指导下提供了链接. :)
【解决方案2】:

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

ef bb bf

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

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

【讨论】:

  • 你如何从这里获取字符串?我可以看到 equals 和 hashCode 不匹配,但找不到这个隐藏的字符...
  • @JordiCastilla 复制粘贴到 hexdump
  • ...虽然现在看来 BOM 在@ErikKralj 的编辑中丢失了。无论如何,它在原始版本中。
【解决方案3】:

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

你能告诉我们path.getBytes()path2.getBytes(),输出数组数据吗?

【讨论】:

  • 原来是导致不相等字符串的编码,这也是由此产生的。抱歉回复晚了,我正在研究所有可能的解决方案,还没有看到你的帖子。谢谢!
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

    你可以尝试做的是

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

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

    【讨论】:

    • android studio 说它无法用两个字符串解析构造函数,并且删除 UTF-8 的引号也不起作用
    【解决方案6】:

    你可以这样做:

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

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

    【讨论】:

      猜你喜欢
      • 2014-02-06
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 2021-02-02
      • 2021-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多