Перейти: Удаление акцентов из строк

#go

#Вперед

Вопрос:

Я новичок в Go и пытаюсь реализовать функцию для преобразования символов с ударением в их эквивалент без акцента. Я пытаюсь следовать примеру, приведенному в этом блоге (см. заголовок «Выполнение магии»).

Что я попытался извлечь из этого, так это:

 package main

import (
    "fmt"
    "unicode"
    "bytes"
    "code.google.com/p/go.text/transform"
    "code.google.com/p/go.text/unicode/norm"
)


func isMn (r rune) bool {
        return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
    }

func main() {
    r := bytes.NewBufferString("Your Śtring")
    t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
    r = transform.NewReader(r, t)
    fmt.Println(r)
}
  

Это ни в малейшей степени не работает, и я, честно говоря, все равно не знаю, что это значит. Есть идеи?

Ответ №1:

Обратите внимание, что в Go 1.5 (август 2015) или Go 1.6 (1 квартал 2016) может появиться новый пакет runes с операциями преобразования.

Это включает (в runes/example_test.go ) runes.Remove функцию, которая поможет преобразовать résumé в resume :

 func ExampleRemove() {
    t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
    s, _, _ := transform.String(t, "résumé")
    fmt.Println(s)

    // Output:
    // resume
}
  

Хотя это все еще рассматривается (апрель 2015).

Ответ №2:

r должно быть или type io.Reader , и вы не можете напечатать r таким образом. Сначала вам нужно прочитать содержимое с точностью до байтового фрагмента:

  var (   
         s = "Your Śtring"
         b = make([]byte, len(s))

         r io.Reader = strings.NewReader(s)
 ) 
 t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
 r = transform.NewReader(r, t)
 r.Read(b)
 fmt.Println(string(b))
  

Это работает, но по какой-то причине возвращает мне «Your Stri» на два байта меньше, чем необходимо.

Это версия, которая на самом деле делает то, что вам нужно, но я все еще не уверен, почему пример из блога работает так странно.

 s := "Yoùr Śtring"
b := make([]byte, len(s))

t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
_, _, e := t.Transform(b, []byte(s), true)
if e != nil { panic(e) }

fmt.Println(string(b))
  

Комментарии:

1. Обратите внимание, хотя transform.NewReader (или transform.NewWriter ) предпочтительнее, если есть какой-либо способ «потоковой передачи» данных (например, для преобразования данных во время чтения / записи из / в файл или сеть), если вы хотите иметь дело только с существующим []byte или string , пакет transform также предоставляет transform.Bytes и transform.String .

2. Прямой вызов метода transform подобным образом — не очень хорошая идея!

3. Причина, по которой вы получаете меньше байтов, чем ожидаете, заключается в том, что вы не все считываете из программы чтения. Самое простое «исправление» вашего существующего кода — заменить вызов read на io.ReadFull(r, b) , но это все еще делает предположения о конечной длине, есть лучшие способы сделать это.