2014-12-23 7 views
1

Я пытаюсь написать функциюКак получить первый «полный» характер руны []?

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, потому что первые две руны дают первый символ Ä. Если бы я только взял первую руну, я бы получил А, что неверно.

Мне нужен ответ на этот вопрос, потому что имя, которое я хочу анонимизировать, может начинаться с акцентированного персонажа, и я не хочу удалять акцент.

ответ

2

Вы можете попробовать следующую функцию (вдохновленный "Go language string length"):

func FirstGraphemeLen(str string) int { 
    re := regexp.MustCompile("\\PM\\pM*|.") 
    return len([]rune(re.FindAllString(str, -1)[0])) 
} 

См this example:

r := []rune{0x0041, 0x0308, 0x0066, 0x0041, 0x0308, 0x0067} 
s := string(r) 
fmt.Println(s, len(r), FirstGraphemeLen(s)) 

Выход:

ÄfÄg 6 2 

Эта строка может использовать 6 рун , но его первая графема использует 2.


OP FUZxxl используется другой подход, с использованием 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, '.') 
/* ... */ 
+0

Это помогло, хотя я не использовал регулярное выражение в реальном коде. Вот [как я это сделал] (http://play.golang.org/p/yjzmGsqltG). – fuz

+0

@FUZxxl IsMark тоже работает. Я включил ваше решение в ответ для большей наглядности. – VonC

+0

Благодарим вас за полировку этого ответа. – fuz