如何识别和替换 Java 字符串中的奇怪字符
How to identify and replace strange character in Java string
我在使用 Java 识别和替换出现在我的文本文件中的特定字符时遇到问题。它是一个不可打印的字符,但似乎 Java 在输出到控制台时将其呈现为 –。
好像是这个角色:https://www.fileformat.info/info/unicode/char/c296/index.htm
这是我所做的:
- 我复制了文件并删除了其中的所有内容,除了我正在努力处理的单个字符。
- 在 UltraEdit 中打开文件。它似乎是一个空文件。
- 将 UltraEdit 更改为“十六进制模式”,现在它显示为两个字符:– 十六进制值为 0xC296(或“C2”代表  字符,“96”代表“–”字符) .
- 我写了下面的 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训练刷房子:
- 拿一罐油漆。
- 拿一根炸药。
- 把罐子放在房间中间。
- 点燃炸药。
- 将炸药放入罐中,大功告成!
...然后收拾残局并修复所有爆炸未引起的区域并扑灭大火。
或者,你知道,也许只是跳过炸药,只买一个油漆工。
这里也一样。首先只需以正确的方式解码这些字节,而不是从墙上刮下油漆和炸药包装纸。
我在使用 Java 识别和替换出现在我的文本文件中的特定字符时遇到问题。它是一个不可打印的字符,但似乎 Java 在输出到控制台时将其呈现为 –。
好像是这个角色:https://www.fileformat.info/info/unicode/char/c296/index.htm
这是我所做的:
- 我复制了文件并删除了其中的所有内容,除了我正在努力处理的单个字符。
- 在 UltraEdit 中打开文件。它似乎是一个空文件。
- 将 UltraEdit 更改为“十六进制模式”,现在它显示为两个字符:– 十六进制值为 0xC296(或“C2”代表  字符,“96”代表“–”字符) .
- 我写了下面的 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训练刷房子:
- 拿一罐油漆。
- 拿一根炸药。
- 把罐子放在房间中间。
- 点燃炸药。
- 将炸药放入罐中,大功告成!
...然后收拾残局并修复所有爆炸未引起的区域并扑灭大火。
或者,你知道,也许只是跳过炸药,只买一个油漆工。
这里也一样。首先只需以正确的方式解码这些字节,而不是从墙上刮下油漆和炸药包装纸。