Java Unicode字符串长度
我想努力得到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:这是泰米尔语。
找到了解决问题的办法。
基于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 – 2013-04-11 13:10:54
是的,我不知道它是否处理所有可能发生在泰米尔语中的情况,但它绝对是优雅的。 – Mifeet 2013-04-11 13:37:59
多么美丽的一组字母! – 2013-04-11 16:32:19
看看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字符类别。
试图规范化字符串和测量的长度。仍然得到它为6.如果浏览器编辑器可以将其识别为3个字符与光标导航,我们有没有在java中的标准方法来获取它? – user1611248 2013-04-11 12:10:16
在这种情况下这是不正确的,但对其他问题很好的提示。 +1 – 2013-04-11 13:05:32
编辑完成后:我监督了那个,也可能用于其他语言。 – 2013-04-11 13:17:34
这原来是真的丑 .... 我已经调试您的字符串,它包含以下字符(和它们的十六进制位置):
க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;
}
你需要排除的组合字符,并相应地计数。
如前所述,您的字符串包含6个不同的代码点。其中一半是字母,另一半是元音符号。 (组合标志)
你可以使用transformations内置到ICU4J库,删除所有的元音符号不属于使用规则快报:
[:^信:]删除
和计数结果字符串。尝试一下他们的演示站点:
http://demo.icu-project.org/icu-bin/translit
我不会结果字符串显示给最终用户的,我不是专家,所以规则可能需要进行调整,以获得一般的案件,但这是一个想法。
它没有任何区别的问题,但有没有必要使用'新的String(“...”)'只是:'String str1 =“குமார்”;' – Jesper 2013-04-11 11:52:32
有关此问题的论文,请参见http://www.venkatarangan.com/blog/content/binary/Counting%20Letters%20in%20an%20Unicode%20String.pdf。 – halex 2013-04-11 11:55:15
博客真的非常丰富。但是它并没有给我们一个java选项来将字符串分成三个有意义的字符。 – user1611248 2013-04-11 12:11:19