Если последовательность кодовых точек образует символ Unicode, каждый ли непустой префикс этой последовательности также образует допустимый символ? - PullRequest
3 голосов
/ 20 апреля 2020

Проблема, с которой я столкнулся, состоит в том, что, учитывая последовательность байтов, я хочу определить ее самый длинный префикс, который формирует действительный символ Unicode (кластер расширенного графема) в предположении кодировки UTF8.

Я использую Swift, поэтому я хотел бы использовать встроенные функции Swift для этого. Но эти функции декодируют только полную последовательность байтов. Таким образом, я думал преобразовать префиксы последовательности байтов через Swift и взять последний префикс, который не дал сбоя и состоит только из 1 символа. Очевидно, что это может привести к испытанию всей последовательности байтов, чего я хочу избежать. Решение состоит в том, чтобы прекратить пробовать префиксы после сбоя 4 префиксов подряд. Если свойство, заданное в моем вопросе, остается в силе, это гарантирует, что все более длинные префиксы также не будут работать.

Я считаю Unicode Text Segmentation Standard нечитаемым, иначе я бы попытался напрямую реализовать определение границ кластеров расширенных графем ...

1 Ответ

0 голосов
/ 20 апреля 2020

После тщательного изучения спецификации для вычислений границ для кластеров расширенных графем (EGCs) в https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules становится очевидным, что правила для EGC имеют форму описания, когда разрешено добавлять кодовую точку к существующему EG C для формирования более длинного EG C. Из этого факта вытекают два моих вопроса: 1) Да, каждый непустой префикс кодовых точек, которые образуют EG C, также является EG C. 2) Нет, добавив кодовую точку к допустимой строке Unicode, вы не уменьшите ее длину с точки зрения количества EGC, из которых она состоит.

Таким образом, с учетом этого следующий код Swift извлечет самый длинный Unicode символ из начала последовательности байтов (или возвращает ноль, если там нет действительного символа Unicode):

    func lex<S : Sequence>(_ input : S) -> (length : Int, out: Character)? where S.Element == UInt8 {
        // This code works under three assumptions, all of which are true:
        // 1) If a sequence of codepoints does not form a valid character, then appending codepoints to it does not yield a valid character
        // 2) Appending codepoints to a sequence of codepoints does not decrease its length in terms of extended grapheme clusters
        // 3) a codepoint takes up at most 4 bytes in an UTF8 encoding
        var chars : [UInt8] = []
        var result : String = ""
        var resultLength = 0
        func value() -> (length : Int, out : Character)? {
            guard let character = result.first else { return nil }
            return (length: resultLength, out: character)
        }
        var length = 0
        var iterator = input.makeIterator()
        while length - resultLength <= 4 {
            guard let char = iterator.next() else { return value() }
            chars.append(char)
            length += 1
            guard let s = String(bytes: chars, encoding: .utf8) else { continue }
            guard s.count == 1 else { return value() }
            result = s
            resultLength = length
        }
        return value()
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...