计算字符长度的有效方法,具体取决于编码方式

Bal*_*usC 10 java byte character character-encoding

计算字符长度的最有效方法是什么,考虑字符编码?编码只在运行时才知道.例如,在UTF-8中,字符具有可变字节长度,因此需要单独确定每个字符.到目前为止,我已经想出了这个:

char c = getCharSomehow();
String encoding = getEncodingSomehow();
// ...
int length = new String(new char[] { c }).getBytes(encoding).length;
Run Code Online (Sandbox Code Playgroud)

但这在循环中是笨拙和低效的,因为new String每次都需要创建.我在Java API中找不到其他更有效的方法.有一个String#valueOf(char),但根据其来源,它基本上与上面相同.我想这可以通过像位移这样的按位操作来完成,但这是我的弱点,我不确定如何在这里考虑编码:)

如果您对此问题有疑问,请查看此主题.


更新:@Bkkbrad的答案在技术上是最有效的:

char c = getCharSomehow();
String encoding = getEncodingSomehow();
CharsetEncoder encoder = Charset.forName(encoding).newEncoder();
// ...
int length = encoder.encode(CharBuffer.wrap(new char[] { c })).limit();
Run Code Online (Sandbox Code Playgroud)

然而正如@Stephen C指出的那样,这方面存在更多问题.例如,可能需要考虑组合/代理字符.但这是另一个需要在此步骤之前的步骤中解决的问题.

Bkk*_*rad 10

使用CharsetEncoder并重CharBuffer作为输入,并使用ByteBuffer作为输出.

在我的系统上,以下代码需要25秒来编码100,000个单个字符:

Charset utf8 = Charset.forName("UTF-8");
char[] array = new char[1];
for (int reps = 0; reps < 10000; reps++) {
    for (array[0] = 0; array[0] < 10000; array[0]++) {
        int len = new String(array).getBytes(utf8).length;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,以下代码在4秒内完成相同的操作:

Charset utf8 = Charset.forName("UTF-8");
CharsetEncoder encoder = utf8.newEncoder();
char[] array = new char[1];
CharBuffer input = CharBuffer.wrap(array);
ByteBuffer output = ByteBuffer.allocate(10);
for (int reps = 0; reps < 10000; reps++) {
    for (array[0] = 0; array[0] < 10000; array[0]++) {
        output.clear();
        input.clear();
        encoder.encode(input, output, false);
        int len = output.position();
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:为什么仇恨者会讨厌?

这是一个从CharBuffer读取并跟踪代理对的解决方案:

Charset utf8 = Charset.forName("UTF-8");
CharsetEncoder encoder = utf8.newEncoder();
CharBuffer input = //allocate in some way, or pass as parameter
ByteBuffer output = ByteBuffer.allocate(10);

int limit = input.limit();
while(input.position() < limit) {
    output.clear();
    input.mark();
    input.limit(Math.max(input.position() + 2, input.capacity()));
    if (Character.isHighSurrogate(input.get()) && !Character.isLowSurrogate(input.get())) {
        //Malformed surrogate pair; do something!
    }
    input.limit(input.position());
    input.reset();
    encoder.encode(input, output, false);
    int encodedLen = output.position();
}
Run Code Online (Sandbox Code Playgroud)