<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
記錄一下專案對使用者 UGC 文字進行字數限制的具體實現。
不同的產品,出於種種原因,一般都會對使用者輸入的文字內容做字數限制。
回到自己的專案,是一個使用者發帖的業務場景。產品同學給到的要求是:
正常情況下,漢字,Emoji 字元,數位與英文字母都是單獨的字元。這裡 2 個數位/英文算作 1 個字,所以在計算字串長度時,不能夠使用 []rune 強轉後來獲取其長度,而是需要統計出數位與英文字母的數量,再加上其他字元數量,作為其長度。所以,要想實現產品同學的要求,關鍵是需要統計出使用者輸入文字中的數位與英文字母的數量。
在 Golang,一般有兩種方法。
數位和英文字母的 ASCII 碼值我們是知道的,通過對原字串遍歷,便可統計出數位/英文字母的數量。
// GetAlphanumericNumByASCII 根據 ASCII 碼值獲取字母數位數量。 func GetAlphanumericNumByASCII(s string) int { num := int(0) for i := 0; i < len(s); i++ { switch { case 48 <= s[i] && s[i] <= 57: // 數位 fallthrough case 65 <= s[i] && s[i] <= 90: // 大寫字母 fallthrough case 97 <= s[i] && s[i] <= 122: // 小寫字母 num++ default: } } return num } // 或者 // GetAlphanumericNumByASCIIV2 根據 ASCII 碼值獲取字母數位數量。 func GetAlphanumericNumByASCIIV2(s string) int { num := int(0) for _, c := range s { switch { case '0' <= c && c <= '9': fallthrough case 'a' <= c && c <= 'z': fallthrough case 'A' <= c && c <= 'Z': num++ default: } } return num }
我們可以利用 Golang 標準庫包 regexp 獲取指定表示式的字串數量。
// GetAlphanumericNumByRegExp 根據正規表示式獲取字母數位數量。 func GetAlphanumericNumByRegExp(s string) int { rNum := regexp.MustCompile(`d`) rLetter := regexp.MustCompile("[a-zA-Z]") return len(rNum.FindAllString(s, -1)) + len(rLetter.FindAllString(s, -1)) }
我們可以寫個單測來驗證下上面三個函數的正確性。
package string import "testing" func TestGetAlphanumericNumByASCII(t *testing.T) { type args struct { s string } tests := []struct { name string args args want int }{ { name: "包含數位", args: args{"108條梁山好漢"}, want: 3, }, { name: "包含字母", args: args{"一百條梁山man"}, want: 3, }, { name: "包含數位與字母", args: args{"108條梁山man"}, want: 6, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := GetAlphanumericNumByASCII(tt.args.s); got != tt.want { t.Errorf("GetAlphanumericNumByASCII() = %v, want %v", got, tt.want) } }) } } func TestGetAlphanumericNumByASCIIV2(t *testing.T) { type args struct { s string } tests := []struct { name string args args want int }{ { name: "包含數位", args: args{"108條梁山好漢"}, want: 3, }, { name: "包含字母", args: args{"一百條梁山man"}, want: 3, }, { name: "包含數位與字母", args: args{"108條梁山man"}, want: 6, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := GetAlphanumericNumByASCIIV2(tt.args.s); got != tt.want { t.Errorf("GetAlphanumericNumByASCII() = %v, want %v", got, tt.want) } }) } } func TestGetAlphanumericNumByRegExp(t *testing.T) { type args struct { s string } tests := []struct { name string args args want int }{ { name: "包含數位", args: args{"108條梁山好漢"}, want: 3, }, { name: "包含字母", args: args{"一百條梁山man"}, want: 3, }, { name: "包含數位與字母", args: args{"108條梁山man"}, want: 6, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := GetAlphanumericNumByRegExp(tt.args.s); got != tt.want { t.Errorf("GetAlphanumericNumByRegExp() = %v, want %v", got, tt.want) } }) } }
執行go test main/string
命令,其中 main/string 為單元測試所在包的路徑。輸出如下:
ok main/string 0.355s
驗證無誤。
上面提到的兩種方法都可以用來獲取字串中數位與英文字母的數量,那麼我們應該採用哪一種方法呢?
功能上沒有差別,那麼我們來看下效能對比吧。
func BenchmarkGetAlphanumericNumByASCII(b *testing.B) { for n := 0; n < b.N; n++ { GetAlphanumericNumByASCII("108條梁山man") } } func BenchmarkGetAlphanumericNumByASCIIV2(b *testing.B) { for n := 0; n < b.N; n++ { GetAlphanumericNumByASCIIV2("108條梁山man") } } func BenchmarkGetAlphanumericNumByRegExp(b *testing.B) { for n := 0; n < b.N; n++ { GetAlphanumericNumByRegExp("108條梁山man") } }
執行上面的基準測試,輸出如下:
go test -bench=. -benchmem main/string
goos: windows
goarch: amd64
pkg: main/string
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkGetAlphanumericNumByASCII-8 89540210 12.67 ns/op 0 B/op 0 allocs/op
BenchmarkGetAlphanumericNumByASCIIV2-8 63227778 19.11 ns/op 0 B/op 0 allocs/op
BenchmarkGetAlphanumericNumByRegExp-8 465954 2430 ns/op 1907 B/op 27 allocs/op
PASS
ok main/string 3.965s
不測不知道,一測嚇一跳。通過正規表示式的實現方式,程式碼雖然簡潔,但是涉及多次記憶體配分,效能與 ASCII 碼值法相比,差距非常之大,是 ASCII 碼值法的 200 倍左右。所以從效能的考慮,推薦使用 ASCII 碼值的方式獲取數位字母數量。
ASCII 碼值法有兩種遍歷方式,一種是按照位元組遍歷,一種是按照 rune 字元遍歷。因為後者涉及 rune 字元的判斷,所以效能會差一些。推薦使用按照位元組遍歷。
本文給出了兩種從字串獲取數位與字母數量的方法:
出於效能的考慮,推薦使用 ASCII 碼值法,並使用位元組遍歷的方式。
此外,本文給出的兩種方法,三種實現方式,相關原始碼已放置開源庫 go-huge-util,可 import 直接使用。
package main import ( "fmt" huge "github.com/dablelv/go-huge-util" ) func main() { fmt.Println(huge.GetAlphanumericNumByASCII("108條梁山man")) // 6 fmt.Println(huge.GetAlphanumericNumByASCIIV2("108條梁山man")) // 6 fmt.Println(huge.GetAlphanumericNumByRegExp("108條梁山man")) // 6 }
到此這篇關於Golang 統計字串中數位字母數量的文章就介紹到這了,更多相關Golang 統計字串內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45