[英]How can I convert a Java string to xml entities for versions of Unicode beyond 3.0?
要将Java字符转换为xml实体,我可以对String中的每个字符执行以下操作:
buf.append("&#x"+ Integer.toHexString(c | 0x10000).substring(1) +";");
但是,根据其他stackoverflow问题,这仅适用于Unicode 3.0。
如果我使用UTF-8 Reader读取字符串,则可能是字符串包含的字符格式可以通过Unicode 6.0进行工作(因为根据Javadoc,Java 7支持Unicode 6.0)。
一旦有了该字符串,如何将其写为xml实体? 理想情况下,我会使用一些会随着新版本的unicode推出而继续工作的api。
您使用的术语不正确,或者这里存在很多混乱。
&#x
字符引用符号仅指定数字代码点; 它独立于任何阅读器或解析器使用的Unicode版本。
您的代码实际上仅与Unicode 1.x兼容,因为它假定字符的数字值小于2 16 。 从Unicode 2.0开始,这不是正确的假设。 一些字符由单个Java char
,而其他字符由两个Java char
(称为代理 )表示。
我不确定“ UTF-8阅读器”是什么。 读取器仅读取char
值,并且不知道UTF-8或任何其他字符集,除了InputStreamReader之外, InputStreamReader使用CharsetDecoder使用UTF-8编码(或特定CharsetDecoder使用的任何编码)将字节转换为char。
无论如何,任何Reader都不会解析XML &#x
字符引用符号。 您必须为此使用XML解析器。
没有读取器或XML解析器受Java已知的Unicode版本的影响,因为没有读取器或XML解析器以任何方式查询Unicode数据库。 字符在解析时仅被视为数字值。 永远不会考虑它们是否与任何Unicode版本中的已分配代码点相对应。
最后,要将String编写为XML,可以使用Formatter :
static String toXML(String s) {
Formatter formatter = new Formatter();
int len = s.length();
for (int i = 0; i < len; i = s.offsetByCodePoints(i, 1)) {
int c = s.codePointAt(i);
if (c < 32 || c > 126 || c == '&' || c == '<' || c == '>') {
formatter.format("&#x%x;", c);
} else {
formatter.format("%c", c);
}
}
return formatter.toString();
}
如您所见,没有代码依赖于Unicode版本,因为字符只是数字值。 每个数字值是否是分配的Unicode代码点都无关紧要。
(我的第一个倾向是使用XMLStreamWriter类,但是事实证明,使用Java-8或更高版本的XMLStreamWriter使用ISO-8859-1或US-ASCII之类的非Unicode编码不能正确地将代理对作为单个字符实体输出。 .0_05。)
最初,Java通过将char类型的长度设置为16位来支持Unicode 1.0,但是Unicode 2.0引入了替代字符机制来支持比16位所允许的数目更多的字符,因此Java字符串成为UTF-16编码。 这意味着某些字符需要两个Java字符来表示,它们分别称为高代理字符和低代理字符。
要知道字符串中的哪些字符实际上是高/低代理对,可以在Character
使用实用程序方法:
Character.isHighSurrogate(myChar); // returns true if myChar is a high surrogate
Character.isLowSurrogate(myChar); // same for low surrogate
Character.isSurrogate(myChar); // just to know if myChar is a surrogate
一旦知道哪些字符是高或低代理,就需要使用以下方法将每对转换为Unicode代码点:
int codePoint = Character.toCodePoint(highSurrogate, lowSurrogate);
因为一段代码值一千个单词,所以这是一个示例方法,用于替换字符串中非us-ascii字符的xml字符引用:
public static String replaceToCharEntities(String str) {
StringBuilder result = new StringBuilder(str.length());
char surrogate = 0;
for(char c: str.toCharArray()) {
// if char is a high surrogate, keep it to match it
// against the next char (low surrogate)
if(Character.isHighSurrogate(c)) {
surrogate = c;
continue;
}
// get codePoint
int codePoint;
if(surrogate != 0) {
codePoint = Character.toCodePoint(surrogate, c);
surrogate = 0;
} else {
codePoint = c;
}
// decide wether using just a char or a character reference
if(codePoint < 0x20 || codePoint > 0x7E || codePoint == '<'
|| codePoint == '>' || codePoint == '&' || codePoint == '"'
|| codePoint == '\'') {
result.append(String.format("&#x%x;", codePoint));
} else {
result.append(c);
}
}
return result.toString();
}
下一个字符串示例是一个很好的示例,因为它包含一个可以用16位值表示的非ASCII字符,以及一个具有高/低代理对的字符:
String myString = "text with some non-US chars: 'Ñ' and '𐌈'";
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.