使用声明的encoding = utf-8 - Java从xml中删除非UTF-8字符

时间:2010-05-19 20:19:03

标签: java xml encoding utf-8

我必须在Java中处理这个场景:

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

让我们考虑这个无效XML包含£(磅)的示例。

1)我将xml作为带有£的java String(我现在无法访问接口,但我可能将xml作为java String)。我可以使用replaceAll(£,“”)来摆脱这个角色吗?任何潜在的问题?

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

6 个答案:

答案 0 :(得分:25)

  

1)我将xml作为带有£的java String(我现在无法访问接口,但我可能将xml作为java String)。我可以使用replaceAll(£,“”)来摆脱这个角色吗?

我假设你想要摆脱非 ASCII 字符,因为你在谈论的是“传统”方面。您可以使用以下正则表达式删除printable ASCII range之外的任何内容:

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

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

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

E.g。

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]", "");
        // ...
    }
    // ...

答案 1 :(得分:17)

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

答案 2 :(得分:7)

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

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

答案 3 :(得分: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。

- 卡皮尔

答案 4 :(得分:1)

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

虽然他们解决了这个问题,但您只需编写一个小程序来更改标题部分,以声明编码是ISO-8859-1:

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

并保持其余部分不受影响。

答案 5 :(得分:1)

在java机器上将字节数组转换为String后,您将获得(默认情况下在大多数计算机上)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
                , ""));
    }

要使整个网络应用程序兼容UTF8,请在此处阅读:
How to get UTF-8 working in Java webapps
More on Byte Encodings and Strings
您可以检查您的模式here PHP here中也是如此。