Подстрока Java по индексам кодовой точки (обработка пар суррогатных единиц кода как единой кодовой точки) - PullRequest
2 голосов
/ 13 апреля 2019

У меня есть небольшое демонстрационное приложение, показывающее проблемы с реализацией подстроки Java при использовании кодовых точек Юникода, которые требуют суррогатных пар (т.е. не могут быть представлены в 2 байта).Мне интересно, работает ли мое решение хорошо или я что-то упускаю.Я рассмотрел возможность публикации в Codereview, но это гораздо больше связано с реализацией Java строк, чем с моим простым кодом.

public class SubstringTest {
    public static void main(String[] args) {

        String stringWithPlus2ByteCodePoints = "????";

        String substring1 = stringWithPlus2ByteCodePoints.substring(0, 1);
        String substring2 = stringWithPlus2ByteCodePoints.substring(0, 2);
        String substring3 = stringWithPlus2ByteCodePoints.substring(1, 3);

        System.out.println(stringWithPlus2ByteCodePoints);
        System.out.println("invalid sub" + substring1);
        System.out.println("invalid sub" + substring2);
        System.out.println("invalid sub" + substring3);

        String realSub1 = getRealSubstring(stringWithPlus2ByteCodePoints, 0, 1);
        String realSub2 = getRealSubstring(stringWithPlus2ByteCodePoints, 0, 2);
        String realSub3 = getRealSubstring(stringWithPlus2ByteCodePoints, 1, 3);
        System.out.println("real sub:"  + realSub1);
        System.out.println("real sub:"  + realSub2);
        System.out.println("real sub:"  + realSub3);
    }

    private static String getRealSubstring(String string, int beginIndex, int endIndex) {
        if (string == null)
            throw new IllegalArgumentException("String should not be null");
        int length = string.length();
        if (endIndex < 0 || beginIndex > endIndex || beginIndex > length || endIndex > length)
            throw new IllegalArgumentException("Invalid indices");
        int realBeginIndex = string.offsetByCodePoints(0, beginIndex);
        int realEndIndex = string.offsetByCodePoints(0, endIndex);
        return string.substring(realBeginIndex, realEndIndex);
    }

}

Вывод:

????
invalid sub: ?
invalid sub: ?
invalid sub: ??
real sub: ?
real sub: ??
real sub: ??

Могу ли я полагатьсяв моей реализации подстроки, чтобы всегда давать желаемую подстроку, которая позволяет избежать проблем Java с использованием символов в качестве метода подстроки?

1 Ответ

2 голосов
/ 14 апреля 2019

Нет необходимости идти к beginIndex дважды:

    public String codePointSubstring(String s, int start, int end) {
        int a = s.offsetByCodePoints(0, start);
        return s.substring(a, s.offsetByCodePoints(a, end - start));
    }

В переводе из этого фрагмента Scala:

def codePointSubstring(s: String, begin: Int, end: Int): String = {
  val a = s.offsetByCodePoints(0, begin)
  s.substring(a, s.offsetByCodePoints(a, end - begin))
}

Я опустил IllegalArgumentException s, потому что они неКажется, он содержит больше информации, чем исключения, которые все равно будут выброшены.

...