Java Unicodestring长度
我正在努力获得Unicodestring的计数,并尝试各种选项。 看起来像一个小问题,但大大的打击。
在这里,我正在尝试获取stringstr1的长度。 我得到它为6.但实际上是3.移动光标在string“குமார்”也显示为3个字符。
基本上我想测量的长度和打印每个字符。 如“கு”,“ாா”,“ர்”。
public class one { public static void main(String[] args) { String str1 = new String("குமார்"); System.out.print(str1.length()); } }
PS:这是泰米尔语。
find解决您的问题。
基于这个答案,我做了一个程序,使用正则expression式字符类来search可能有可选修饰符的字母。 它将你的string分割成单个(如果需要的话)字符并把它们放到一个列表中:
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/Apkapn以获得工作演示;
编辑
我现在用http://en.wikipedia.org/wiki/Tamil_script中的表格中所有有效的泰米尔语字母来检查我的正则expression式。; 我发现用当前的正则expression式我们不能正确捕获所有的字母(Grantha化合物表中最后一行的每个字母被分成两个字母),所以我将我的正则expression式改进为以下解决scheme:
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);
看看Normalizer类。 有什么可能是你的问题的原因的解释。 在Unicode中,可以通过多种方式对字符进行编码,例如: Á
:
U+00C1 LATIN CAPITAL LETTER A WITH ACUTE
要么
U+0041 LATIN CAPITAL LETTER A U+0301 COMBINING ACUTE ACCENT
您可以尝试使用Normalizer
将string转换为组合forms,然后迭代字符。
编辑:根据上面的@halexbuild议的文章,在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);
我得到的结果是[கு, மா, ர்]
。 如果它不适用于所有的string,请尝试使用if
块中的其他Unicode字符类别。
这真的很丑….我已经debugging你的string,它包含以下字符(及其hex位置):
க0x0b95
ு0x0bc1
ம0x0bae
ா0x0bbe
ர0x0bb0
0x0bcd
所以泰米尔语言显然使用了类似于变音符的序列来获取所有不幸被算作单独实体的字符。
UTF-8 / UTF-16不是UTF-8 / UTF-16的问题,它被其他答案所错误地声称,它在泰米尔语的Unicode编码中是固有的。
build议的Normalizer不起作用,似乎tamil是由Unicode“专家”devise的,以明确使用不能被标准化的组合序列。 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]
由于字形相交,所以您需要像使用其他解决scheme一样使用Java字符types函数。
解:
我正在使用此链接: 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; }
您需要排除组合字符并相应地进行计数。
如前所述,您的string包含6个不同的代码点。 一半是字母,另一半是元音符号。 (合并商标)
您可以使用内置于ICU4J库中的转换,使用以下规则删除所有不是字母的元音符号:
[:^信:]删除
并计算结果string。 在演示网站上试用一下:
http://demo.icu-project.org/icu-bin/translit
我不会把结果string显示给最终用户,而且我也不是专家,所以规则可能需要调整以适应一般情况,但这是一个想法。