当前位置: 首页 > 知识库问答 >
问题:

Java Unicode字符串长度

封昊天
2023-03-14

我正在努力获取unicode字符串的计数,并尝试了各种选项。看起来是个小问题,但影响很大。

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

基本上我想测量长度并打印每个字符。像 "கு", "மா", "ர்" .

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

附言:这是泰米尔语。

共有3个答案

宓文斌
2023-03-14

这真的很难看。。。。我已经调试了您的字符串,它包含以下字符(及其十六进制位置):

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

所以泰米尔语显然使用类似变音符号的序列来获得所有不幸被算作独立实体的字符。

这不是UTF-8/UTF-16的问题,正如其他答案错误地宣称的那样,这是泰米尔语言的Unicode编码固有的。

建议的规范化器不起作用,似乎泰米尔语是由Unicode“专家”设计的,以明确使用无法规范化的组合序列。啊。

我的下一个想法不是计算字符,而是字形,字符的视觉表现。

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]

由于glyph是相交的,所以需要像在另一个解决方案中一样使用Java字符类型函数。

解决方案:

我正在使用这个链接:http://www.venkatarangan.com/blog/content/binary/CountingUnicode字符串中的字母。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;
  }

您需要排除组合字符,并相应地进行计数。

红甫
2023-03-14

看看Normalizer类。你的问题可能是由什么原因造成的,这里有一个解释。在Unicode中,可以用几种方式对字符进行编码,例如Á

  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字符类别。

阴阳
2023-03-14

找到了解决你问题的方法。

基于这个答案,我制作了一个程序,使用正则表达式字符类来搜索可能有可选修饰符的字母。它将字符串拆分为单个字符(必要时组合),并将它们放入列表中:

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.我发现使用当前的正则表达式无法正确捕获所有字母(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);
 类似资料:
  • 要求出字符串的长度(字符的个数),我们可以使用length函数。调用这个函数的语法和我们前面看到的有点不同: int length; length = fruit.length(); 对于这种函数调用,我们称之为在字符串变量fruit上**调用(invoke)**length函数。“调用(invoke)”这个词可能看起来有点奇怪,但是后面我们还会遇到很多在对象上调用函数的例子。 函数调用的语法称

  • 问题内容: 如果长度超过10个字符,我想修剪字符串。 假设字符串长度为12(),则新的修剪后的字符串将包含。 我该如何实现? 问题答案: s = s.substring(0, Math.min(s.length(), 10)); 这样使用字符串可以避免在字符串已经短于的情况下出现异常。 笔记: 上面做了真正的修剪。如果您实际上想将截断的最后三个(!)字符替换为点,请使用Apache Commons

  • 大家好。我必须制作这个程序,输入一个文本,输出有多少个单词,以及有多少个长度为1、2等的单词。我已经完成了计算单词数的程序,但对于第二部分我不知道。非常感谢任何能帮忙的人。

  • 问题内容: 有没有办法在不知道字符串长度的情况下,将一个字符长的字符串切成4个字符串,每个字符长? 例如: 问题答案:

  • 问题内容: 我正在寻找一种方法来限制php中的字符串,并在字符串过长时在末尾添加…。 问题答案: 您可以使用类似于以下内容的东西:

  • 我正在努力获取unicode字符串的计数,并尝试了各种选项。看起来是个小问题,但影响很大。 这里我试图得到字符串str1的长度。我得到的是6分。但实际上是3。将光标移到字符串上“குமார்“也显示为3个字符。 基本上我想测量长度并打印每个字符。像 "கு", "மா", "ர்" . 附言:这是泰米尔语。