Java正则表达式匹配器在BMP之外断开字符
我目前正在编写一个util类来清理输入,该类保存到xml文档中。对我们来说,清理意味着所有非法字符()都将从字符串中删除 我试图通过使用一些正则表达式来实现这一点,它将所有无效字符替换为空字符串,但对于BMP之外的unicode字符,这似乎以某种方式破坏了编码,留给我的是那些Java正则表达式匹配器在BMP之外断开字符,java,regex,xml,supplementary,Java,Regex,Xml,Supplementary,我目前正在编写一个util类来清理输入,该类保存到xml文档中。对我们来说,清理意味着所有非法字符()都将从字符串中删除 我试图通过使用一些正则表达式来实现这一点,它将所有无效字符替换为空字符串,但对于BMP之外的unicode字符,这似乎以某种方式破坏了编码,留给我的是那些?字符。用regexp替换的方式似乎也无关紧要(String#replaceAll(String,String),Pattern#compile(String),org.apache.commons.lang3.RegExU
?
字符。用regexp替换的方式似乎也无关紧要(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'
}
}
我现在有了一个解决方案,从单个代码点重建整个字符串,但这似乎不是正确的解决方案
提前谢谢 没有正则表达式的解决方案可能是经过过滤的代码点流:
publicstaticstringsanitize\uxml\u10(字符串输入){
返回input.codePoints()
.filter(测试::allowedXml10)
.collect(StringBuilder::new、StringBuilder::appendCodePoint、StringBuilder::append)
.toString();
}
私有静态布尔允许XML10(int代码点){
如果(0x0009==codepoint)返回true;
如果(0x000A==codepoint)返回true;
如果(0x000D==codepoint)返回true;
如果(0x0020不带正则表达式的解决方案可能是经过过滤的代码点流:
publicstaticstringsanitize\uxml\u10(字符串输入){
返回input.codePoints()
.filter(测试::allowedXml10)
.collect(StringBuilder::new、StringBuilder::appendCodePoint、StringBuilder::append)
.toString();
}
私有静态布尔允许XML10(int代码点){
如果(0x0009==codepoint)返回true;
如果(0x000A==codepoint)返回true;
如果(0x000D==codepoint)返回true;
如果(0x0020经过一些读取和实验后,对正则表达式进行轻微更改(将\x{..}
替换为代理项\u..\u...
有效:
private静态最终模式XML\u 10\u 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
经过一些阅读和实验后,对Regex稍作修改(将\x{..}
替换为代理项\u..\u..
有效:
private静态最终模式XML\u 10\u 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
根据,正则表达式应该使用“外部”字符。你确定这不仅仅是字体问题吗?我也这么认为(一开始),但测试结果有所不同。where块的最后一个条目失败。这些表情符号属于D7FF和E000之间的禁止范围,应该根本无法通过。如果我在它们周围插入空格,那么结果只会是空格。因此Java在一起写入时对字符串的解释不同。甚至打印cod“\uD83E\uDDD1\uD83C\uDFFB”
中的epoint显示0x1f9d1
和0x1f3fb
。emojis是有效的XML。正如您在第二篇文章中所述,它们在允许的范围0x10000到0x10FFFF之间。这也在Wikipedia文章中有说明。根据和正则表达式应与“outside”一起使用字符。你确定这不仅仅是字体问题吗?我也这么认为(一开始),但测试结果有所不同。where块的最后一个条目失败。这些表情符号属于D7FF和E000之间的禁止范围,应该根本无法通过。如果我在它们周围插入空格,那么结果只会是空格。因此Java在一起写入时对字符串的解释不同。甚至打印cod“\uD83E\uDDD1\uD83C\uDFFB”中的epoint
显示了0x1f9d1
和0x1f3fb
。emojis是有效的XML。正如您在第二篇文章中所述,它们在允许的范围0x10000到0x10FFFF之间。这在维基百科文章中也有说明。是的,这基本上就是我所做的。它是有效的。但奇怪的是,在字符串级别上已经不可能做到这一点了。耶啊,这基本上就是我所做的。它是有效的。但感觉很奇怪,在字符串级别上已经不可能这样做了。好的,基本上就是这样。奇怪的是,我必须从字符点组中删除所有转义,但不允许从单个字符点中删除它们。所以工作的正则表达式是[^\u0009\u000A\u000D--�好的,基本上就是这样。奇怪的是,我不得不从字符点组中删除所有转义符,但不允许从单个字符点中删除它们。因此工作正则表达式是[^\u0009\u000A\u000D--�