Как получить первый "полный" символ руны?

Я пытаюсь написать функцию

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, '.')
/* ... */
Другие вопросы по тегам