我试图从字符串中分割出所有中文字符,但我遇到了一个奇怪的角色情况
scala> ""
res1: String =
scala> res1.length
res2: Int = 2
scala> res1.getBytes
res3: Array[Byte] = Array(-16, -91, -111, -82)
scala> res1(0)
res4: Char = ?
scala> res1(1)
res5: Char = ?
它是一个单个字符,但Java / Scala将其确定为两个未知字符。通常我看到中文字符在UTF-8中占用三个字节,但这个字符需要四个字节。
因此,我无法拆分字符串并找到这个单字符。更糟糕的是,当使用myString.replaceAll("[^\\p{script=Han}]", "")
踢出所有非中文字符时,第二部分被替换,它变成无效的字符串。
这有什么解决方案吗?我在Ubuntu上使用openjdk-8-jdk。
答案 0 :(得分:8)
如果长度你应该使用
string.codePointCount(0, string.length());
对于替换,最好避免使用基于字符的正则表达式。您可以根据String#offsetByCodePoints()
编写一个循环,并根据String.codePointAt()
和Character.isIdeographic()
手动删除字符。
答案 1 :(得分:3)
您遇到了代理对。该字符为U+2546E,如您所见,比2 ^ 16大很多。它在Java或Scala字符串中表示为序列0xD855 0xDC6E。
如果你想要一个透明地处理这类事情的正则表达式库,我碰巧知道在哪里找到一个:TCL regex ported to Java。如果你不想去那里,你需要使用java中String和Character的Code Point方法进行导航。
答案 2 :(得分:1)
Java标准库unicode支持早于当前标准,因此对星体(非BMP)字符的支持是有限的;如您所见,几个API会将它们视为单独的代理对。如果你正在进行大量的字符串操作,最好使用ICU4J,我理解它提供完全unicode支持的正则表达式。
答案 3 :(得分:0)
基于@Marko的回答,这是一个分割字符串的例子:
scala> val x = "硓abc"
x: String = 硓abc
scala> (0 to x.codePointCount(0, x.length)).map(c => x.offsetByCodePoints(0, c)).sliding(2).map(w => x.substring(w.head, w.last)).toList
res1: List[String] = List(硓, , a, b, c)
并确定每个角色是否为CJKV:
scala> (0 until x.codePointCount(0, x.length)).map(c => x.offsetByCodePoints(0, c)).map(i => Character.isIdeographic(x.codePointAt(i))).toList
res2: List[Boolean] = List(true, true, false, false, false)
答案 4 :(得分:-2)
我认为你想要替换/拆分字符串。你可以在不知道字符串长度的情况下做。因为java也需要字符串序列来替换字符串中特定的char或char序列。例如:-`public class Test {
public static void main(String[] args) {
String s="";
System.out.println(s.replace("", "k"));
}
}
` 如果你想拆分String,那就去找stringtokenizer。例如: -
StringTokenizer st= new StringTokenizer("your sentence or String","the problematic char/string");
答案 5 :(得分:-3)
可能此字符在UTF-8中无效或不受支持但在UTF-16中受支持,导致JVM和Scala shell之间存在某些不兼容性。你的系统是大端还是小端?您也可以尝试获取角色的Unicode代码点,并检查它是UTF-8还是UTF-16。此外,中文复杂的字母,如日语汉字和Furigana,所以这也可能是你问题的一部分。