Как получить первый "полный" символ руны?
Я пытаюсь написать функцию
func Anonymize(name string) string
это анонимизирует имена. Вот несколько примеров пар ввода и вывода, поэтому вы получите представление о том, что он должен делать:
Müller → M.
von der Linden → v. d. L.
Meyer-Schulze → M.-S.
Эта функция должна работать с именами, составленными из произвольных символов. При реализации этой функции у меня возник следующий вопрос:
Учитывая []rune
или же string
Как выяснить, сколько рун мне нужно взять, чтобы получить полный символ, полный в том смысле, что все модификаторы и сочетания акцентов, соответствующие символу, тоже взяты. Например, если вход []rune{0x0041, 0x0308, 0x0066, 0x0067}
(соответствует строке ÄBC, где Ä представляется как сочетание A и объединяющего диареза), функция должна возвращать 2, потому что первые две руны дают первый символ Ä. Если бы я только взял первую руну, я бы получил А, что неверно.
Мне нужен ответ на этот вопрос, потому что имя, которое я хочу анонимизировать, может начинаться с акцентированного символа, и я не хочу удалять акцент.
1 ответ
Вы можете попробовать следующую функцию (вдохновлено " Длина строки языка Go "):
func FirstGraphemeLen(str string) int {
re := regexp.MustCompile("\\PM\\pM*|.")
return len([]rune(re.FindAllString(str, -1)[0]))
}
Смотрите этот пример:
r := []rune{0x0041, 0x0308, 0x0066, 0x0041, 0x0308, 0x0067}
s := string(r)
fmt.Println(s, len(r), FirstGraphemeLen(s))
Выход:
ÄfÄg 6 2
Эта строка может использовать 6 рун, но ее первая графема использует 2.
fuz использовал другой подход, используя unicode.IsMark(r)
IsMark
сообщает, является ли руна символом метки (категория М).
Источник (из play.golang.org FUZxxl) включает в себя:
// take one character including all modifiers from the last name
r, _, err := ln.ReadRune()
if err != nil {
/* ... */
}
aln = append(aln, r)
for {
r, _, err = ln.ReadRune()
if err != nil {
goto done
}
if !unicode.IsMark(r) {
break
}
aln = append(aln, r)
}
aln = append(aln, '.')
/* ... */