Вы можете попробовать RuneCountInString
из пакета utf8.
возвращает количество рун в р
что, как показано в этом сценарии : длина «Мира» может быть 6 (если написано по-китайски: «世界»), но число рун равно 2:
package main
import "fmt"
import "unicode/utf8"
func main() {
fmt.Println("Hello, 世界", len("世界"), utf8.RuneCountInString("世界"))
}
Фрозен добавляет в комментарии :
На самом деле вы можете делать len()
руны, просто набирая тип.
len([]rune("世界"))
напечатает 2
. По латы в Go 1.3.
И с CL 108985 (май 2018, для Go 1.11), len([]rune(string))
теперь оптимизирован. ( Исправляет проблему 24923 )
Компилятор len([]rune(string))
автоматически обнаруживает шаблон и заменяет его на вызов r: = range s.
Добавляет новую функцию времени выполнения для подсчета рун в строке. Модифицирует компилятор для обнаружения шаблона len([]rune(string))
и заменяет его новой функцией времени выполнения подсчета рун.
RuneCount/lenruneslice/ASCII 27.8ns ± 2% 14.5ns ± 3% -47.70% (p=0.000 n=10+10)
RuneCount/lenruneslice/Japanese 126ns ± 2% 60ns ± 2% -52.03% (p=0.000 n=10+10)
RuneCount/lenruneslice/MixedLength 104ns ± 2% 50ns ± 1% -51.71% (p=0.000 n=10+9)
Стефан Штайгер указывает на сообщение в блоге « Нормализация текста в Go »
Что такое персонаж?
Как было упомянуто в посте блога , символы могут охватывать несколько рун .
Например, ' e
' и '◌́◌́' (острый "\ u0301") могут объединиться, чтобы сформировать "é" (" e\u0301
" в NFD). Вместе эти две руны - один персонаж .
Определение символа может варьироваться в зависимости от приложения.
Для нормализации мы определим это как:
- последовательность рун, которая начинается со стартера,
- руна, которая не изменяет и не комбинирует в обратном направлении с любой другой руной,
- сопровождаемый возможно пустой последовательностью не начальных символов, то есть рун, которые делают (обычно акценты).
Алгоритм нормализации обрабатывает один символ за раз.
Используя этот пакет и его Iter
тип , фактическое количество символов будет:
package main
import "fmt"
import "golang.org/x/text/unicode/norm"
func main() {
var ia norm.Iter
ia.InitString(norm.NFKD, "école")
nc := 0
for !ia.Done() {
nc = nc + 1
ia.Next()
}
fmt.Printf("Number of chars: %d\n", nc)
}
Здесь используется форма нормализации Unicode NFKD «Декомпозиция совместимости»
Oliver «s ответ указывает на UNICODE TEXT СЕГМЕНТАЦИИ как единственный способ надежно определить границы по умолчанию между некоторыми значительными элементами текста: пользовательские воспринимаемых символов, слов и фраз.
Для этого вам нужна внешняя библиотека, такая как rivo / uniseg , которая выполняет Unicode Text Segmentation .
Это фактически будет считать « кластер графем », где несколько кодовых точек могут быть объединены в один воспринимаемый пользователем символ.
package uniseg
import (
"fmt"
"github.com/rivo/uniseg"
)
func main() {
gr := uniseg.NewGraphemes("👍🏼!")
for gr.Next() {
fmt.Printf("%x ", gr.Runes())
}
// Output: [1f44d 1f3fc] [21]
}
Две графемы, хотя есть три руны (кодовые точки Unicode).
Вы можете увидеть другие примеры в " Как манипулировать строками в GO, чтобы обратить их вспять? "
👩🏾🦰 только одна графема, но, от юникода до конвертора кодовых точек , 4 руны: