从 xml 中删除声明的编码 = utf-8 的非 UTF-8 字符 - Java

问题描述 投票:0回答:7

我必须用Java处理这个场景:

我从客户端收到 XML 形式的请求,声明的编码为 utf-8。不幸的是,它可能不包含 utf-8 字符,并且需要从我这边的 xml 中删除这些字符(遗留)。

让我们考虑一个示例,其中该无效 XML 包含 £(英镑)。

1)我将 xml 作为 java 字符串获取,其中包含 £(我现在无法访问接口,但我可能将 xml 作为 java 字符串获取)。我可以使用replaceAll(£, "") 来删除这个字符吗?有任何潜在的问题吗?

2)我得到 xml 作为字节数组 - 在这种情况下如何安全地处理此操作?

java xml encoding utf-8
7个回答
35
投票

1)我将 xml 作为 java 字符串获取,其中包含 £(我现在无法访问接口,但我可能将 xml 作为 java 字符串获取)。我可以使用replaceAll(£, "") 来删除这个字符吗?

我假设你的意思是你想要摆脱非ASCII字符,因为你正在谈论“遗留”方面。您可以使用以下正则表达式删除可打印 ASCII 范围之外的任何内容:

string = string.replaceAll("[^\\x20-\\x7e]", "");

2)我得到 xml 作为字节数组 - 在这种情况下如何安全地处理此操作?

您需要将

byte[]
包装在
ByteArrayInputStream
中,以便您可以使用
InputStreamReader
在 UTF-8 编码字符流中读取它们,其中您指定编码,然后使用
BufferedReader
逐行阅读。

例如

BufferedReader reader = null;
try {
    reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8"));
    for (String line; (line = reader.readLine()) != null;) {
        line = line.replaceAll("[^\\x20-\\x7e]", "");
        // ...
    }
    // ...

20
投票

UTF-8是一种编码; Unicode 是一种字符集。但 GBP 符号绝对位于 Unicode 字符集中,因此也绝对可以用 UTF-8 表示。

如果您实际上指的是 UTF-8,并且您实际上正在尝试删除不是 UTF-8 中字符的有效编码的字节序列,那么...

CharsetDecoder utf8Decoder = Charset.forName("UTF-8").newDecoder();
utf8Decoder.onMalformedInput(CodingErrorAction.IGNORE);
utf8Decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
ByteBuffer bytes = ...;
CharBuffer parsed = utf8Decoder.decode(bytes);
...

10
投票
"test text".replaceAll("[^\\u0000-\\uFFFF]", "");

此代码从字符串中删除所有 4 字节 utf8 字符。在执行 Mysql innodb varchar 条目时可能需要出于某些目的


3
投票

我在从本地目录读取文件时遇到了同样的问题并尝试了以下方法:

BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document xmlDom = db.parse(new InputSource(in));

您可能必须使用网络输入流而不是 FileInputStream。

-- 卡皮尔


2
投票

请注意,第一步应该是您要求 XML 的创建者(很可能是一个本土的“仅打印数据”XML 生成器)在发送给您之前确保其 XML 是正确的。如果他们使用 Windows,最简单的测试就是要求他们在 Internet Explorer 中查看并查看第一个违规字符处的解析错误。

虽然他们解决了这个问题,但您可以简单地编写一个小程序来更改标头部分以声明编码为 ISO-8859-1:

<?xml version="1.0" encoding="iso-8859-1" ?>

其余部分保持不变。


1
投票

在 java 机器上将字节数组转换为字符串后,您将获得(默认情况下在大多数机器上)UTF-16 编码的字符串。摆脱非 UTF-8 字符的正确解决方案是使用以下代码:

String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa"};
for (int i = 0; i < values.length; i++) {
    System.out.println(values[i].replaceAll(
                    "[\\\\x00-\\\\x7F]|" + //single-byte sequences   0xxxxxxx
                    "[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences   110xxxxx 10xxxxxx
                    "[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences   1110xxxx 10xxxxxx * 2
                    "[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
            , ""));
}

或者如果你想验证某个字符串是否包含非 utf8 字符,你可以使用 Pattern.matches ,例如:

String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa"};
for (int i = 0; i < values.length; i++) {
    System.out.println(Pattern.matches(
                    ".*(" +
                    "[\\\\x00-\\\\x7F]|" + //single-byte sequences   0xxxxxxx
                    "[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences   110xxxxx 10xxxxxx
                    "[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences   1110xxxx 10xxxxxx * 2
                    "[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
                    + ").*"
            , values[i]));
}

如果您有可用的字节数组,那么您可以使用以下方法更正确地过滤它们:

BufferedReader bufferedReader = null;
try {
    bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8"));
    for (String currentLine; (currentLine = bufferedReader.readLine()) != null;) {
        currentLine = currentLine.replaceAll(
                        "[\\x00-\\x7F]|" + //single-byte sequences   0xxxxxxx
                        "[\\xC0-\\xDF][\\x80-\\xBF]|" + //double-byte sequences   110xxxxx 10xxxxxx
                        "[\\xE0-\\xEF][\\x80-\\xBF]{2}|" + //triple-byte sequences   1110xxxx 10xxxxxx * 2
                        "[\\xF0-\\xF7][\\x80-\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
                , ""));
    }

要使整个 Web 应用程序兼容 UTF8,请阅读此处:
如何让 UTF-8 在 Java Web 应用程序中工作
有关字节编码和字符串的更多信息
您可以在此处检查您的图案。
PHP 中也是如此这里


0
投票
ChatGPT to the rescue:

public String removeNonAsciiCharacters(final String inString) {
    if (null == inString) return null;
   
    String cleanedString = inString.replaceAll("[^\\p{ASCII}]", "");
    
    return cleanedString;
}

此代码使用replaceAll()方法将所有不在ASCII字符集中的字符替换为空字符串。正则表达式中的 \p{ASCII} 匹配任何 ASCII 字符

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.