Java RegEx 匹配器会破坏 BMP 之外的字符

标签 java regex xml supplementary

我目前正在编写一个 util 类来清理输入,并将其保存到 xml 文档中。对我们来说,清理意味着所有非法字符( https://en.wikipedia.org/wiki/Valid_characters_in_XML#XML_1.0 )都会从字符串中删除。

我试图通过使用一些正则表达式来做到这一点,它将所有无效字符替换为空字符串,但是对于 BMP 之外的 unicode 字符,这似乎以某种方式破坏了编码,让我留下了那些 字符。我使用哪种正则表达式替换方式似乎并不重要 (String#replaceAll(String, String), Pattern#compile(String), org .apache.commons.lang3.RegExUtil#removeAll(String, String))

这是一个带有测试的示例实现(在 Spock 中),它显示了问题: XmlStringUtil.java

package com.example.util;

import lombok.NonNull;

import java.util.regex.Pattern;

public class XmlStringUtil {

    private static final Pattern XML_10_PATTERN = Pattern.compile(
        "[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD\\x{10000}-\\x{10FFFF}]"
    );

    public static String sanitizeXml10(@NonNull String text) {
        return XML_10_PATTERN.matcher(text).replaceAll("");
    }

}

XmlStringUtilSpec.groovy

package com.example.util

import spock.lang.Specification

class XmlStringUtilSpec extends Specification {

    def 'sanitize string values for xml version 1.0'() {
        when: 'a string is sanitized'
            def sanitizedString = XmlStringUtil.sanitizeXml10 inputString

        then: 'the returned sanitized string matches the expected one'
            sanitizedString == expectedSanitizedString

        where:
            inputString                                | expectedSanitizedString
            ''                                         | ''
            '\b'                                       | ''
            '\u0001'                                   | ''
            'Hello World!\0'                           | 'Hello World!'
            'text with emoji \uD83E\uDDD1\uD83C\uDFFB' | 'text with emoji \uD83E\uDDD1\uD83C\uDFFB'
    }

}

我现在有了一个解决方案,可以从单个代码点重建整个字符串,但这似乎不是正确的解决方案。

提前致谢!

最佳答案

经过一些阅读和实验,对正则表达式进行了轻微更改(将 \x{..} 替换为代理项 \u...\u... 作品:

private static final Pattern XML_10_PATTERN = Pattern.compile(
        "[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD\uD800\uDC00-\uDBFF\uDFFF]"
    );

检查:

sanitizeXml10("\uD83E\uDDD1\uD83C\uDFFB").codePoints().mapToObj(Integer::toHexString).forEach(System.out::println);

结果

1f9d1
1f3fb

关于Java RegEx 匹配器会破坏 BMP 之外的字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56276144/

相关文章:

java - Log4j2 + Java:以编程方式添加asyncLogger

java - ArrayList.add 抛出 ArrayIndexOutOfBoundsException

java - 如何将这个包装 map 列表展平为另一种 map Java 8?

regex - 将单词括在单引号中的 Bash 脚本

java - 从linux连接到access数据库

Java - 模式匹配

具有多个类的 jQuery 元素 : storing one class as a var

c# - 获取深度嵌入的 XML 元素值

c++ - Boost ptree 读取 xml 中的结束标记 xml 验证不正确

java - 仅使用 Java 制作 ImageView 抖动