#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)
, но это все еще делает предположения о конечной длине, есть лучшие способы сделать это.