UTF8 Длина строки и индексы в Go против Swift - PullRequest
0 голосов
/ 02 мая 2018

У меня есть приложения в Go и Swift, которые обрабатывают строки, такие как поиск подстрок и их индексов. Сначала он работал хорошо даже с многобайтовыми символами (например, emojis), используя Go * utf8.RuneCountInString() и родную строку Swift.

Но есть некоторые символы UTF8, которые разбивают длину строки и индексы для подстрок, например, строка "Lorem ??✌️? ipsum":

Go's utf8.RuneCountInString("Lorem ??✌️? ipsum") возвращает 17, а начальный индекс ipsum равен 12.

Свифт "Lorem ??✌️? ipsum".count возвращает 16, а начальный индекс ipsum равен 11.

Использование Swift String utf8, utf16 или приведение к NSString дает также различные длины и индексы. Есть и другие смайлики, составленные из множества других смайликов типа ?‍?‍?‍?, которые дают еще более смешные цифры.

Это с Go 1.8 и Swift 4.1.

Есть ли способ получить одинаковые длины строк и индексы подстрок с одинаковыми значениями с помощью Go и Swift?

EDIT

Я создал расширение Swift String на основе замечательного ответа @ MartinR:

extension String {
    func runesRangeToNSRange(from: Int, to: Int) -> NSRange {
        let length = to - from
        let start = unicodeScalars.index(unicodeScalars.startIndex, offsetBy: from)
        let end = unicodeScalars.index(start, offsetBy: length)
        let range = start..<end

        return NSRange(range, in: self)
    }
}

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

В Swift Character - это «расширенный кластер графем», и каждый из «?», «?», «✌️», «?», «?‍?‍?‍?» считается одним символом ,

У меня нет опыта работы с Go, но, насколько я понимаю, из Строки, байты, руны и символы в Go , «Руна» - это кодовая точка Unicode, которая по существу соответствует UnicodeScalar в Swift.

В вашем примере разница происходит от "✌️", который считается как один символ Swift, но построен из двух скаляров Unicode:

print("✌️".count) // 1
print("✌️".unicodeScalars.count) // 2

Вот пример того, как вы можете вычислить длину и смещения в условия Unicode скаляры:

let s = "Lorem ??✌️? ipsum"
print(s.unicodeScalars.count) // 17

if let idx = s.range(of: "ipsum") {
    print(s.unicodeScalars.distance(from: s.startIndex, to: idx.lowerBound)) // 12
}

Как видите, это дает те же цифры, что и в вашем примере с Go.

0 голосов
/ 02 мая 2018

A rune в Go идентифицирует конкретную кодовую точку UTF-8 ; это не обязательно означает, что он отображает 1: 1 на визуально отличающиеся символы. Некоторые символы могут состоять из нескольких рун / кодовых точек, поэтому подсчет рун может не дать того, чего вы ожидаете от визуального осмотра строки. Я не знаю, что на самом деле имеет значение "some text".count в Свифте, поэтому я не могу предложить никакого сравнения там.

...