2013-04-11 224 views
55

我想努力得到unicode字符串的计数并尝试了各种选项。看起来像一个小问题,但以一个很大的方式。Java Unicode字符串长度

这里我试图获取字符串str1的长度。我得到它为6.但实际上它是3.移动光标在字符串“குமார்”也显示为3个字符。

基本上我想测量长度并打印每个字符。如“கு”,“ாா”,“ர்”。

public class one { 
    public static void main(String[] args) { 
      String str1 = new String("குமார்"); 
      System.out.print(str1.length()); 
    } 
} 

PS:这是泰米尔语。

+18

它没有任何区别的问题,但有没有必要使用'新的String(“...”)'只是:'String str1 =“குமார்”;' – Jesper 2013-04-11 11:52:32

+5

有关此问题的论文,请参见http://www.venkatarangan.com/blog/content/binary/Counting%20Letters%20in%20an%20Unicode%20String.pdf。 – halex 2013-04-11 11:55:15

+0

博客真的非常丰富。但是它并没有给我们一个java选项来将字符串分成三个有意义的字符。 – user1611248 2013-04-11 12:11:19

回答

38

找到了解决问题的办法。

基于this SO answer我做了一个程序,使用正则表达式字符类来搜索可能有可选修饰符的字母。这将您的字符串转换成单(如果需要合并)字符,并将它们放入一个列表:

import java.util.*; 
import java.lang.*; 
import java.util.regex.*; 

class Main 
{ 
    public static void main (String[] args) 
    { 
     String s="குமார்"; 
     List<String> characters=new ArrayList<String>(); 
     Pattern pat = Pattern.compile("\\p{L}\\p{M}*"); 
     Matcher matcher = pat.matcher(s); 
     while (matcher.find()) { 
      characters.add(matcher.group());    
     } 

     // Test if we have the right characters and length 
     System.out.println(characters); 
     System.out.println("String length: " + characters.size()); 

    } 
} 

其中\\p{L}意味着一个Unicode字母,\\p{M}意味着一个Unicode标志。

代码段的输出是:

கு 
மா 
ர் 
String length: 3 

了工作演示


编辑

现在我检查我的所有有效的泰米尔语字母的正则表达式取自见https://ideone.com/Apkapnhttp://en.wikipedia.org/wiki/Tamil_script中的表格。我发现,与目前正则表达式不正确(在Grantha复合表最后一行中的每一个字母被分裂成两个字母)捕获所有的信件,让我改进我的正则表达式如下解决方案:

Pattern pat = Pattern.compile("\u0B95\u0BCD\u0BB7\\p{M}?|\\p{L}\\p{M}?"); 

用这个模式代替上面的模式,你应该能够将你的句子分成每个有效的泰米尔语信件(只要维基百科的表格已完成)。

我用来检查代码下列之一:

String s = "ஃஅஆஇஈஉஊஎஏஐஒஓஔக்ககாகிகீகுகூகெகேகைகொகோகௌங்ஙஙாஙிஙீஙுஙூஙெஙேஙைஙொஙோஙௌச்சசாசிசீசுசூசெசேசைசொசோசௌஞ்ஞஞாஞிஞீஞுஞூஞெஞேஞைஞொஞோஞௌட்டடாடிடீடுடூடெடேடைடொடோடௌண்ணணாணிணீணுணூணெணேணைணொணோணௌத்ததாதிதீதுதூதெதேதைதொதோதௌந்நநாநிநீநுநூநெநேநைநொநோநௌப்பபாபிபீபுபூபெபேபைபொபோபௌம்மமாமிமீமுமூமெமேமைமொமோமௌய்யயாயியீயுயூயெயேயையொயோயௌர்ரராரிரீருரூரெரேரைரொரோரௌல்லலாலிலீலுலூலெலேலைலொலோலௌவ்வவாவிவீவுவூவெவேவைவொவோவௌழ்ழழாழிழீழுழூழெழேழைழொழோழௌள்ளளாளிளீளுளூளெளேளைளொளோளௌற்றறாறிறீறுறூறெறேறைறொறோறௌன்னனானினீனுனூனெனேனைனொனோனௌஶ்ஶஶாஶிஶீஶுஶூஶெஶேஶைஶொஶோஶௌஜ்ஜஜாஜிஜீஜுஜூஜெஜேஜைஜொஜோஜௌஷ்ஷஷாஷிஷீஷுஷூஷெஷேஷைஷொஷோஷௌஸ்ஸஸாஸிஸீஸுஸூஸெஸேஸைஸொஸோஸௌஹ்ஹஹாஹிஹீஹுஹூஹெஹேஹைஹொஹோஹௌக்ஷ்க்ஷக்ஷாக்ஷிக்ஷீக்ஷுக்ஷூக்ஷெக்ஷேக்ஷைஷொக்ஷோஷௌ"; 
List<String> characters = new ArrayList<String>(); 
Pattern pat = Pattern.compile("\u0B95\u0BCD\u0BB7\\p{M}?|\\p{L}\\p{M}?"); 
Matcher matcher = pat.matcher(s); 
while (matcher.find()) { 
    characters.add(matcher.group()); 
} 

System.out.println(characters); 
System.out.println(characters.size() == 325); 
+1

不错! +1 – 2013-04-11 13:10:54

+1

是的,我不知道它是否处理所有可能发生在泰米尔语中的情况,但它绝对是优雅的。 – Mifeet 2013-04-11 13:37:59

+0

多么美丽的一组字母! – 2013-04-11 16:32:19

15

看看Normalizer课程。有什么可能是你的问题的原因解释。在Unicode中,您可以通过多种方式对字符进行编码,e.g Á

U+00C1 LATIN CAPITAL LETTER A WITH ACUTE 

U+0041 LATIN CAPITAL LETTER A 
    U+0301 COMBINING ACUTE ACCENT 

你可以尝试使用Normalizer到您的字符串转换为组成形式,然后遍历字符。


编辑:基于以上通过建议@halex文章,试试这个在Java中:

String str = new String("குமார்"); 

    ArrayList<String> characters = new ArrayList<String>(); 
    str = Normalizer.normalize(str, Form.NFC); 
    StringBuilder charBuffer = new StringBuilder(); 
    for (int i = 0; i < str.length(); i++) { 
     int codePoint = str.codePointAt(i); 
     int category = Character.getType(codePoint); 
     if (charBuffer.length() > 0 
       && category != Character.NON_SPACING_MARK 
       && category != Character.COMBINING_SPACING_MARK 
       && category != Character.CONTROL 
       && category != Character.OTHER_SYMBOL) { 
      characters.add(charBuffer.toString()); 
      charBuffer.delete(0, charBuffer.length()); 
     } 
     charBuffer.appendCodePoint(codePoint); 
    } 
    if (charBuffer.length() > 0) { 
     characters.add(charBuffer.toString()); 
    } 
    System.out.println(characters); 

结果我得到的是[கு, மா, ர்]。如果它不适用于所有字符串,请尝试使用if块中的其他Unicode字符类别。

+4

试图规范化字符串和测量的长度。仍然得到它为6.如果浏览器编辑器可以将其识别为3个字符与光标导航,我们有没有在java中的标准方法来获取它? – user1611248 2013-04-11 12:10:16

+2

在这种情况下这是不正确的,但对其他问题很好的提示。 +1 – 2013-04-11 13:05:32

+0

编辑完成后:我监督了那个,也可能用于其他语言。 – 2013-04-11 13:17:34

8

这原来是真的 .... 我已经调试您的字符串,它包含以下字符(和它们的十六进制位置):

க0x0b95
ு0x0bc1
ம0x0bae
ா0x0bbe
ர0x0bb0
்0x0bcd

所以泰米尔语显然使用变音符号般的序列得到 所有字符,不幸算作单独的实体。

这不是UTF-8/UTF-16的问题,如 其他答案所声称的,它是泰米尔 语言的Unicode编码中固有的。

建议的Normalizer不起作用,似乎泰米尔有 已由Unicode“专家”设计明确使用不能正常化的组合 序列。 AARGH。

我的下一个想法是不指望字符,但字形,人物的视觉 表示。

String str1 = new String(Normalizer.normalize("குமார்", Normalizer.Form.NFC)); 

Font display = new Font("SansSerif",Font.PLAIN,12); 
GlyphVector vec = display.createGlyphVector(new FontRenderContext(new AffineTransform(),false, false),str1); 

System.out.println(vec.getNumGlyphs()); 
for (int i=0; i<str1.length(); i++) 
     System.out.printf("%s %s %s %n",str1.charAt(i),Integer.toHexString((int) str1.charAt(i)),vec.getGlyphVisualBounds(i).getBounds2D().toString()); 

其结果是:

கB95 [X = 0.0,Y = -6.0,W = 7.0,H = 6.0]
ுBC1 [X = 8.0,Y = -6.0,W = 7.0,h = 4.0]
மbae [x = 17.0,y = -6.0,w = 6.0,h = 6.0]
bbe [x = 23.0,y = -6.0,w = 5.0,h = 6.0]
ரBB0 [X = 30.0,Y = -6.0,W = 4.0,H = 8.0]
்BCD [X = 31.0,Y = -9.0,W = 1.0,H = 2.0]

作为GL yphs正在相交,您需要使用Java字符类型 函数,就像在其他解决方案中一样。

SOLUTION:

我使用这个链接:http://www.venkatarangan.com/blog/content/binary/Counting%20Letters%20in%20an%20Unicode%20String.pdf

public static int getTamilStringLength(String tamil) { 
    int dependentCharacterLength = 0; 
    for (int index = 0; index < tamil.length(); index++) { 
     char code = tamil.charAt(index); 
     if (code == 0xB82) 
      dependentCharacterLength++; 
     else if (code >= 0x0BBE && code <= 0x0BC8) 
      dependentCharacterLength++; 
     else if (code >= 0x0BCA && code <= 0x0BD7) 
      dependentCharacterLength++; 
    } 
    return tamil.length() - dependentCharacterLength; 
    } 

你需要排除的组合字符,并相应地计数。

2

如前所述,您的字符串包含6个不同的代码点。其中一半是字母,另一半是元音符号。 (组合标志)

你可以使用transformations内置到ICU4J库,删除所有的元音符号不属于使用规则快报:

[:^信:]删除

和计数结果字符串。尝试一下他们的演示站点:

http://demo.icu-project.org/icu-bin/translit

我不会结果字符串显示给最终用户的,我不是专家,所以规则可能需要进行调整,以获得一般的案件,但这是一个想法。

+5

它是否包含6个字符或3个字符完全取决于您对“字符”的定义。不幸的是,这个词没有很好的定义,并以各种不兼容的方式使用。如果您将“字符”表示为“代码点”,则您的声明才是正确的。 – delnan 2013-04-11 12:53:11

+0

啊是的。编辑。 – Charlie 2013-04-11 13:15:42