如何识别和替换 Java 字符串中的奇怪字符

How to identify and replace strange character in Java string

我在使用 Java 识别和替换出现在我的文本文件中的特定字符时遇到问题。它是一个不可打印的字符,但似乎 Java 在输出到控制台时将其呈现为 –。

好像是这个角色:https://www.fileformat.info/info/unicode/char/c296/index.htm

这是我所做的:

  1. 我复制了文件并删除了其中的所有内容,除了我正在努力处理的单个字符。
  2. 在 UltraEdit 中打开文件。它似乎是一个空文件。
  3. 将 UltraEdit 更改为“十六进制模式”,现在它显示为两个字符:– 十六进制值为 0xC296(或“C2”代表  字符,“96”代表“–”字符) .
  4. 我写了下面的 Java 程序试图将这个字符更改为可打印的字符,但我没有成功。

代码如下:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileTester {
    public static void main(String[] args) throws IOException {

        String filePath = "c:/temp/bad-file.txt";
        byte[] data = Files.readAllBytes(Paths.get(filePath));
        System.out.println("Array 0: " + data[0]);
        System.out.println("Array 1: " + data[1]);
        String content = new String(data);
    
        System.out.println(content);
        System.out.println(content.replace("0xC296", "BadCharacter"));
        System.out.println(content.replace("0xec8a96", "BadCharacter"));
        System.out.println(content.replace("\uC296", "BadCharacter"));
    }
}

这是输出:

Array 0: -62
Array 1: -106
–
–
–
–

下面是 UltraEdit 如何以十六进制模式显示此文件的图片:

请让我知道我做错了什么。

private static String cleanTextContent(String text) 
    {
    // strips off all non-ASCII characters
    text = text.replaceAll("[^\x00-\x7F]", "");

    // erases all the ASCII control characters
    text = text.replaceAll("[\p{Cntrl}&&[^\r\n\t]]", "");
 
    // removes non-printable characters from Unicode
    text = text.replaceAll("\p{C}", "");

    return text.trim();
    }

您可以使用正则表达式删除或替换不可打印的字符。

这是一个字符集问题。确保使用正确的字符集读取文件。

在字符集Windows-1252, bytes C2 96 are characters  (U+00C2: Latin Capital Letter A with Circumflex) and (U+2013中:En Dash).

在字符集ISO 8859-1中,字节96未定义。字节 C2Â,与 Windows-1252 相同。

字符集 UTF-8, bytes C2 96 is the encoding of Unicode code point U+0096<保护区开始> (SPA))。

字符集中UTF-16BE, bytes C2 96 is the encoding of character (U+C296: not valid). In character set UTF-16LE, they would decode as character (U+96C2:汉字).

问题代码使用了new String(byte[]),使用的是平台默认的字符集,所以单从代码看不清楚使用的是哪个字符集。

因为它在 Windows 上是 运行,并且打印为 –,所以它似乎使用了字符集 Windows-1252。因此,要替换使用该字符集读取文件所产生的字符对,请使用:

content.replace("\u00C2\u2013", "BadCharacter")

如果 Java 代码使用 UTF-8 读取文件,通过调用 new String(data, StandardCharsets.UTF_8),代码应该是:

content.replace("\u0096", "BadCharacter")

仅供参考: UltraEdit 可能使用 UTF-8 打开文件,这就是为什么它看起来是一个空文件的原因。请参阅“Unicode text and Unicode files in UltraEdit”以了解有关 UltraEdit 如何处理 Unicode 文件的更多信息。

I am having trouble using Java to identify and replacing a specific character that appears in a text file I have. It is a non-printable character, but it seems that Java renders it as – when outputting to the console.

It seems to be this character: https://www.fileformat.info/info/unicode/char/c296/index.htm

我来翻译:

乔说:“我有一个正方形。它是一个圆”。

你发表了相互矛盾的陈述。它是一个 non-printable 字符,还是完全可打印的 슖(看到了吗?我刚刚打印了它),还是完全不同的东西,它在文件中显示为 0xC2 96,您会立即跳转到结论是这一定意味着它是 슖 因为它的 unicode 编号是 0xC296?

在您将其称为 'bad file' 之前,它只是一个编码文件,您只需对其应用正确的编码即可。

每当字节转换为字符或反之亦然,总是应用字符集转换。你不能不这样做。因此,在 new String(bytes) 中,是的,应用了字符集转换。哪一个?好吧,'platform default',这只是 'the wrong answer' 的一种有趣的说法。你永远不想默认播放形式。永远不要调用 new String(bytes),这是一个你永远不应该使用的愚蠢方法。

不幸的是,纯文本文件没有随数据一起标记的编码。除非您已经知道您拥有的编码,否则您无法阅读 .txt 文件。如果你不知道,你就无法阅读它,或者,如果你不知道但你对文件中的内容有一个很好的了解,你可以进入夏洛克福尔摩斯模式并尝试弄清楚它。

你告诉 java 它是用 'platform default' 编码的,不管它是什么(看起来像 ISO-8859-1 或 Win-1252),你得到了垃圾,但那是因为你指定了错误的编码,而不是因为 'java is bad' 或 'the file is bad'。只需指定正确的编码,一切如雨后春笋。

使用一些著名的文本编辑器(例如 SublimeText、cot 编辑器、notepad++ 等)打开文件,并调整编码值直到文本有意义。

必须使用您的人脑(这对计算机来说是相当困难的人工智能!)并查看文件并做出有根据的猜测。例如,如果我在一个文件中看到 Mç~ller,其中这些是起源于欧洲的姓氏似乎是合乎逻辑的,那可能是 Müller,那么现在我可以尝试反向求解(查找十六进制序列,然后抛出序列 + ü 在网络搜索引擎中,它通常会告诉你该怎么做),或者继续在我的编辑器中选择编码,直到我看到 Müller 出现,现在我知道了。

因此,如果您这样做了,并且确实确定了 슖 是有意义的,好吧,对此进行回溯,这里唯一有意义的编码是 UTF-16BE。所以,把它扔进你的编辑器,或者使用 new String(thoseBytes, "UTF-16BE") 看看这些东西现在是否有意义。

在任何情况下,您都不应该按照这些其他答案的建议去做,即您使用错误的编码读取文件,然后尝试清理由此产生的史诗般的混乱。有点像Mr Bean sketch训练刷房子:

  1. 拿一罐油漆。
  2. 拿一根炸药。
  3. 把罐子放在房间中间。
  4. 点燃炸药。
  5. 将炸药放入罐中,大功告成!

...然后收拾残局并修复所有爆炸未引起的区域并扑灭大火。

或者,你知道,也许只是跳过炸药,只买一个油漆工。

这里也一样。首先只需以正确的方式解码这些字节,而不是从墙上刮下油漆和炸药包装纸。