2017-09-26 1154 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

這是迄今爲止最簡單的方法,但它確實有一些缺點。但是,對於短字符串,缺點是最壞的問題是小問題。 –