Go:为 code.google.com/p/go.text/transform 制作转换器

标签 go

一段时间以来,我一直在通过以下方式对文本进行规范化和去重音处理:

// Local helper function for normalization of UTF8 strings.
func isMn (r rune) bool {
        return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
    }

// This map is used by RemoveAccents function to convert non-accented characters.
var transliterations = map[rune]string{'Æ':"E",'Ð':"D",'Ł':"L",'Ø':"OE",'Þ':"Th",'ß':"ss",'æ':"e",'ð':"d",'ł':"l",'ø':"oe",'þ':"th",'Œ':"OE",'œ':"oe"}

//  removeAccentsBytes converts accented UTF8 characters into their non-accented equivalents, from a []byte.
func removeAccentsBytesDashes(b []byte) ([]byte, error) {
    mnBuf := make([]byte, len(b))
    t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
    n, _, err := t.Transform(mnBuf, b, true)
    if err != nil {
        return nil, err
    }
    mnBuf = mnBuf[:n]
    tlBuf := bytes.NewBuffer(make([]byte, 0, len(mnBuf)*2))
    for i, w := 0, 0; i < len(mnBuf); i += w {
        r, width := utf8.DecodeRune(mnBuf[i:])
        if r=='-' {
            tlBuf.WriteByte(' ')
        } else {
            if d, ok := transliterations[r]; ok {
                tlBuf.WriteString(d)
            } else {
                tlBuf.WriteRune(r)
            }
        }
        w = width
    }
    return tlBuf.Bytes(), nil
}

之后我将整个东西小写并应用一系列正则表达式。

这种做法很重。我认为我应该能够在一个字节循环中完成整个事情,而不是 10 个循环,而且正则表达式很慢。

我的第一个想法是修改上述函数以直接在循环中执行小写(removeAccentsBytes 函数的第二部分)。但后来我决定将它们全部合并到一个循环中,包括转换函数。

关于这一点,我首先尝试从转换源中获取转换表,然后通过复制和修改它,但我似乎无法让它为我提供它用于转换的任何表。事实证明,即使是 norm.NFD = 1 和 norm.NFC = 0,我还没有弄清楚它是如何解析参数为 0 或 1 的事实,并以某种方式从中得到一个转换表。

阅读它的代码我可以看到它无论如何都写得很高效,而且显然超出了初学者的 Go 技能,所以我认为使用 transform.Chain 添加我自己的转换器可能会更好。

我在任何地方都找不到任何关于如何编写 transform.Chain 接受的转换器的说明。什么都没有。

有人知道我如何为此制作变压器吗?

最佳答案

transform.Chain

func Chain(t ...Transformer) Transformer

接受一个 transform.Transformer 的数组

type Transformer interface {
    Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
}

所以你只需要创建一个实现 Transformer 接口(interface)的类型:

type DenormalizeAndDeaccent struct {
}

func (t *DenomarlizeAndDeaccent) Transform(dst, src []byte, atEOF bool) (int, int, error)   {
    result, err := removeAccentsBytesDashes(src)
    if err != nil {
        return 0, 0, nil
    }
    n := copy(dst, result)
    if n < len(src) {
        err = ErrShortDst
    }
    return n, len(src), err
}

关于Go:为 code.google.com/p/go.text/transform 制作转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25403542/

相关文章:

go - 如何避免路由器处理代码中的代码重复

go - conn.SetDeadline() 是否在超时时关闭连接

go - 使用go-sql-driver时如何区分连接错误和其他错误

json - 如何将 header 添加到 JSON 以识别数组值的数组名称

go - 保存类型以供以后反射

go - 如何在函数 panic 之前写入控制台?

go - 如何分析 Golang Web 应用服务器

go - 如何使用多种格式在循环中解析日期?

go - 如何在 IRIS 中禁用自动转义

go - 使用 crypto/ssh 连接到 Cisco 交换机