【问题标题】:creating and using Strings with surrogate pairs使用代理对创建和使用字符串
【发布时间】:2013-09-04 14:05:52
【问题描述】:

我必须使用0FFFF 以上的代码点(特别是数学脚本字符),并且没有找到有关如何执行此操作的简单教程。我希望能够(a)创建具有高代码点的Strings 并(b)迭代其中的字符。由于char 无法保存这些点,我的代码如下所示:

    @Test
public void testSurrogates() throws IOException {
    // creating a string
    StringBuffer sb = new StringBuffer();
    sb.append("a");
    sb.appendCodePoint(120030);
    sb.append("b");
    String s = sb.toString();
    System.out.println("s> "+s+" "+s.length());
    // iterating over string
    int codePointCount = s.codePointCount(0, s.length());
    Assert.assertEquals(3, codePointCount);
    int charIndex = 0;
    for (int i = 0; i < codePointCount; i++) {
        int codepoint = s.codePointAt(charIndex);
        int charCount = Character.charCount(codepoint);
        System.out.println(codepoint+" "+charCount);
        charIndex += charCount;
    }
}

我觉得这要么完全正确,要么是最干净的方法。我会期望诸如codePointAfter() 之类的方法,但只有codePointBefore()。请确认这是正确的策略或提供替代策略。

更新:感谢@Jon 的确认。我为此苦苦挣扎——这里有两个需要避免的错误:

  • 代码点没有直接索引(即没有s.getCodePoint(i)) - 您必须遍历它们
  • 使用(char) 作为强制类型转换会截断0FFFF 以上的整数,而且不容易发现

【问题讨论】:

    标签: java string unicode


    【解决方案1】:

    在我看来是正确的。如果要遍历字符串中的代码点,可以将此代码包装在 Iterable 中:

    public static Iterable<Integer> getCodePoints(final String text) {
        return new Iterable<Integer>() {
            @Override public Iterator<Integer> iterator() {
                return new Iterator<Integer>() {
                    private int nextIndex = 0;
    
                    @Override public boolean hasNext() {
                        return nextIndex < text.length();
                    }
    
                    @Override public Integer next() {
                        if (!hasNext()) {
                            throw new NoSuchElementException();
                        }
                        int codePoint = text.codePointAt(nextIndex);
                        nextIndex += Character.charCount(codePoint);
                        return codePoint;
                    }
    
                    @Override public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }
    

    当然,您也可以将方法更改为只返回int[]

    public static int[] getCodePoints(String text) {
        int[] ret = new int[text.codePointCount(0, text.length())];
        int charIndex = 0;
        for (int i = 0; i < ret.length; i++) {
            ret[i] = text.codePointAt(charIndex);
            charIndex += Character.charCount(ret[i]);
        }
        return ret;
    }
    

    我同意,遗憾的是 Java 库还没有公开这样的方法,但至少它们不是难以编写。

    【讨论】:

      猜你喜欢
      • 2011-12-10
      • 1970-01-01
      • 2014-04-12
      • 2016-11-10
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      • 1970-01-01
      • 2013-12-05
      相关资源
      最近更新 更多