2017-09-26 1153 views
3

我正在尝试编写一个函数来截断golang中包含特殊字符的字符串。一个例子是下面Golang截断具有特殊字符但不破坏数据的字符串

"H㐀〾▓朗퐭텟şüöžåйкл¤"

但是基于允许的字符数我这样做并切断它在中间。这会导致数据被损坏。

结果出来像

H㐀〾▓朗퐭텟şüöžå�...

不应该存在。我们如何检测这些特殊字符并根据这些字符的长度来分割它们?

package main 

import (
    "fmt" 
    "regexp" 
) 

var reNameBlacklist = regexp.MustCompile(`(&|>|<|\/|:|\n|\r)*`) 
var maxFileNameLength = 30 

// SanitizeName sanitizes user names in an email 
func SanitizeName(name string, limit int) string { 

    result := name 
    reNameBlacklist.ReplaceAllString(result, "") 
    if len(result) > limit { 
     result = result[:limit] + "..." 
    } 
    return result 
} 



func main() { 
    str := "H㐀〾▓朗퐭텟şüöžåйкл¤" 
    fmt.Println(str) 

    strsan := SanitizeName(str, maxFileNameLength) 
    fmt.Println(strsan) 

} 

回答

6

切片字符串将它们视为其基础字节数组;切片操作符对字节的索引进行操作,而不是符文(可以是每个字节多个字节)。但是,字符串上的range会在符文上迭代 - 但返回的索引是字节。这使得相当简单,做你要找的内容(full playground example here):

func SanitizeName(name string, limit int) string { 
    reNameBlacklist.ReplaceAllString(name, "") 
    result := name 
    chars := 0 
    for i := range name { 
     if chars >= limit { 
      result = name[:i] 
      break 
     } 
     chars++ 
    } 
    return result 
} 

中对此有详细说明on the Go blog

+0

与问题代码的一个区别是当限制开始时的“...”。我试图从_shortened_字符串中去除黑名单字符,但是您要么改变含义('santitize(“>>> abc“,3)'变成'”...“'而不是'”abc ...“')或者必须使代码复杂化。 – twotwotwo

+0

我们现在的逻辑首先剥离字符串,这就是为什么我保留后来截断 – Sakib

2

您的数据得到破坏的原因是因为一些字符使用一个以上的字节,你正在分裂它们。为了避免这种情况,有类型rune代表一个UTF-8字符。你可以只投的字符串到[]rune这样的:

func SanitizeName(name string, limit int) string{ 
    reNameBlacklist.ReplaceAllString(name, "") 
    result := []rune(name) 
    // Remove the special chars here 
    return string(result[:limit]) 
} 

这应该只留下第一限制 UTF-8字符。

+1

Adrian的方法避免了每个Unicode码点分配四个字节,并且当输入字符串很长时,工作量减少了,所以我会继续这样做。 – twotwotwo

+1

这是迄今为止最简单的方法,但它确实有一些缺点。但是,对于短字符串,缺点是最坏的问题是小问题。 –