通过将emojis仅计为一个字符来获取字符串中正确的字符索引

时间:2017-04-21 09:07:27

标签: java android emoji

我的Android应用程序的问题是,当我计算其中包含emojis的字符串的长度时,每个表情符号计为两个或更多字符。我正在研究具有iOS版本的应用程序的Android版本。 iOS将每个表情符号统计为一个字符 - 当从iOS应用程序返回索引时,它假定每个表情符号都计为一个。

“你好我爱@team”

我想得到@team的索引,当我得到的唯一信息是iOS给出的索引是13,在android上这可能是14甚至15。

3 个答案:

答案 0 :(得分:3)

这个答案建议使用java的Unicode支持代码点

  

表情符号(grapheme)是Unicode 代码点。 Java内部也使用Unicode,但通常为(UTF-16)char一个双字节代码,而表情符号的代码点的Unicode编号要高得多。因此java使用了几个字符。以emojis开头。

但是可以在java中使用代码点。 Java 8有一些额外的帮助;不需要,但我希望Android已经达到了一些功能。

获取代码点的长度:

int codePointsLength(String s) {
    int n = 0;
    for (int i = 0; i < s.length(); ) {
        int codePoint = s.codePointAt(i);
        i += Character.charCount(codePoint);
        ++n;
    }
    return n;
}

int codePointsLength(String s) {
    return (int) s.codePoints().count(); // Java 8.
}

使用Unicode代码点从表情符号创建字符串:

final int RAISED_EYEBROW = 0x1f928; // U+1F928.
String s = new String(new int[] {RAISED_EYEBROW}, 0, 1);

查找由代码点索引的字符串的位置:

int codePointIndexOf(String s, int codePoint) {
    int n = 0;
    for (int i = 0; i < s.length(); ) {
        int cp = s.codePointAt(i);
        if (cp == codePoint) {
            return n;
        }
        i += Character.charCount(cp);
        ++n;
    }
    return -1;
}

// Java 9 takeWhile.
int codePointIndexOf(String s, int codePoint) {
    int totalCount = (int) s.codePoints().count();
    int count = (int) s.codePoints().takeWhile(cp -> cp != codePoint).count();
    return count >= totalCount ? -1 : count;
}

答案 1 :(得分:1)

以为我应该发布我的回答,因为我有两个赞成。

决定最好使用iOS索引作为&#34;真实&#34;和android的索引作为&#34; fake&#34;,这导致我必须将所有内容转换为iOS索引。 graphemeGetIndex获得iOS&#34;真实&#34;来自Java&#34; fake&#34;的索引那些,grahemeGetLength得到了真实的&#34;你需要的长度。

询问您是否有任何问题

public static int graphemeLength(String s) {
        BreakIterator it = BreakIterator.getCharacterInstance();
        it.setText(s);
        int count = 0;
        while (it.next() != BreakIterator.DONE) {
            count++;
        }
        return count;
    }

public static int graphemeGetIndex(String wholeString, int mIndex) {
    BreakIterator it = BreakIterator.getCharacterInstance();
    int realStartIndex = 0;
    if (mIndex >= 0) {
        String partString = wholeString.substring(0, mIndex);
        it.setText(partString);
        while (it.next() != BreakIterator.DONE) {
            realStartIndex++;
        }
    }
    return realStartIndex;
}

private void recalculateIndices() {
        for (final UserMention mention : mMentions) {
            final int startFake = mCurrentText.indexOf("@" + mention.getName());
            final int startReal = graphemeGetIndex(mCurrentText, startFake);
            mention.setRealIndices(new int[]{startReal, startReal + graphemeLength(mention.getName())});
            mention.setJavaFakeIndices(new int[]{startFake, startFake + mention.getName().length()});
        }
    }

答案 2 :(得分:1)

在尝试看到新的表情符号被释放后,我对此的回答是使用维护良好的库:

我导入了该库:

implementation 'com.vdurmont:emoji-java:4.0.0'

然后,我创建了一个实用程序方法来获取将表情符号计数为1的字符串的长度:

fun getLengthWithEmoji(s: String): Int{
        var emojiCount = EmojiParser.extractEmojis(s).size;
        var noEmojiString = EmojiParser.removeAllEmojis(s);
        var emojiAndStringCount = emojiCount + noEmojiString.length;
        return emojiAndStringCount;
}

通常要'获取字符串中的表情符号计数',我会使用此行:

var emojiCount = EmojiParser.extractEmojis(s).size;

这说明了所有最新的表情符号(取决于您的图书馆的最新信息)。检查其他人在库中创建的一些fork,因为在某些情况下它们添加了缺少的表情符号模式。