亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go怎么實現精準統計文章字數

發布時間:2021-06-12 10:40:18 來源:億速云 閱讀:252 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關Go怎么實現精準統計文章字數的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

01 需求分析

下手之前先分析下這個需求。從我個人經驗看,在實際面試中,針對一個面試題,你的分析過程,循序漸進的解決方案,可以很好的展示你的思考過程。正所謂分析問題、解決問題。這會給你加分的。

我們采用類似詞法分析的思路分析這個需求。

一篇文章通常包含如下元素,我們也稱之為 token:

  • 普通文字

  • 標點符號

  • 圖片

  • 鏈接(包含各種協議的鏈接)

  • 代碼

其中普通文字通常會分為歐美和中日韓(CJK),因為 CJK 屬于表意文字,和歐美字母的文字差異很大。同時這里還涉及到編碼的問題。本文假設使用 UTF-8  編碼。

對于標點符號,中文標點和英文標點也會很不一樣。

此外還有全角和半角的問題。

根據以上分析,對于該需求作如下假定:

  • 空格(包括換行)不算字數;

  • HTML 標簽需要剔除;

  • 編碼方式:假定為 UTF-8 編碼;

  • 標點符號算不算做字數。如果算,像括號這樣的按 2 個字算;

  • 鏈接怎么算?一個鏈接約定為 1 個字可能更合適,大概閱讀時只是把它當鏈接,而不太會關心鏈接由什么字母組成;

  • 圖片不算做字數,但如果計算閱讀時間,可能需要適當考慮圖片的影響;

  • 對于技術文章,代碼是最麻煩的。統計代碼字數感覺是沒多大意義的。統計代碼行數可能更有意義;

本文的解決方案針對以上的假定進行。

02 Go 語言實現

先看最簡單的。

純英文

根據以上分析,如果文章只包含普通文本且是英文,也就是說,每個字(單詞)根據空格分隔,統計是最簡單的。

func TotalWords(s string) int {  n := 0  inWord := false  for _, r := range s {   wasInWord := inWord   inWord = !unicode.IsSpace(r)   if inWord && !wasInWord {    n++   }  }  return n }

還有一種更簡單的方式:

len(strings.Fields(s))

不過看 strings.Fields 的實現,性能會不如第一種方式。

回顧上面的需求分析,會發現這個實現是有 Bug 的。比如下面的例子:

s1 := "Hello,playground" s2 := "Hello, playground"

用上面的實現,s1 的字數是 1,s2 的字數是  2。它們都忽略了標點符號。而且因為寫法的多樣性(不規范統一),導致計算字數會有誤差。所以我們需要對寫法進行規范。

規范排版

其實和寫代碼要有規范一樣,文章也是有規范的。比如出版社對于一本書的排版會有明確的規定。為了讓我們的文章看起來更舒服,也應該遵循一定的規范。

這里推薦一個 GitHub  上的排版指南:《中文文案排版指北》,它的宗旨,統一中文文案、排版的相關用法,降低團隊成員之間的溝通成本,增強網站氣質。這個規范開頭關于空格的一段話很有意思:

有研究顯示,打字的時候不喜歡在中文和英文之間加空格的人,感情路都走得很辛苦,有七成的比例會在 34  歲的時候跟自己不愛的人結婚,而其余三成的人最后只能把遺產留給自己的貓。畢竟愛情跟書寫都需要適時地留白。

建議大家可以看看這個指北,一些知名的網站就是按照這個做的。

因為 GCTT 的排版在這個規范做,但人為約束不是最好的方法,所以我開發了一個 Go  工具:https://github.com/studygolang/autocorrect,用于自動給中英文之間加入合理的空格并糾正專用名詞大小寫。

所以為了讓字數統計更準確,我們假定文章是按一定的規范書寫的。比如上面的例子,規范的寫法是 s2 := "Hello,  playground"。不過這里標點不算作字數。

剛去微博上試了一下,發現微博的字數計算方式有點詭異,竟然是 9 個字。

Go怎么實現精準統計文章字數

測試一下發現,它直接把兩個英文字母算作一個字(兩個字節算一個字)。而漢字是正常的。大家可以想想微博是怎么實現的。

中英文混合

中文不像英文,單詞之間沒有空格分隔,因此開始的那兩種方式不適合。

如果是純中文,我們怎么計算字數呢?

在 Go 語言中,字符串使用 UTF-8 編碼,一個字符用 rune 表示。因此在標準庫中查找相關計算方法。

func RuneCountInString(s string) (n int)

這個方法能計算字符串包含的 rune(字符)數,對于純中文,就是漢字數。

str := "你好世界" fmt.Println(utf8.RuneCountInString(str))

以上代碼輸出 4。

然而,因為很多時候文章會中英文混合,因此我們先采用上面的純英文的處理方式,即:strings.Fields(),將文章用空格分隔,然后處理每一部分。

func TotalWords(s string) int {  wordCount := 0     plainWords := strings.Fields(s)  for _, word := range plainWords {   runeCount := utf8.RuneCountInString(word)   if len(word) == runeCount {    wordCount++   } else {    wordCount += runeCount   }  }   return wordCount }

增加如下的測試用例:

func TestTotalWords(t *testing.T) {  tests := []struct {   name  string   input string   want  int  }{   {"en1", "hello,playground", 2},   {"en2", "hello, playground", 2},   {"cn1", "你好世界", 4},   {"encn1", "Hello你好世界", 5},   {"encn2", "Hello 你好世界", 5},  }  for _, tt := range tests {   t.Run(tt.name, func(t *testing.T) {    if got := wordscount.TotalWords(tt.input); got != tt.want {     t.Errorf("TotalWords() = %v, want %v", got, tt.want)    }   })  } }

發現 en1 和 encn1 測試不通過,因為沒有按照上面說的規范書寫。因此我們通過程序增加必要的空格。

// AutoSpace 自動給中英文之間加上空格 func AutoSpace(str string) string {  out := ""   for _, r := range str {   out = addSpaceAtBoundary(out, r)  }   return out }  func addSpaceAtBoundary(prefix string, nextChar rune) string {  if len(prefix) == 0 {   return string(nextChar)  }   r, size := utf8.DecodeLastRuneInString(prefix)  if isLatin(size) != isLatin(utf8.RuneLen(nextChar)) &&   isAllowSpace(nextChar) && isAllowSpace(r) {   return prefix + " " + string(nextChar)  }   return prefix + string(nextChar) }  func isLatin(size int) bool {  return size == 1 }  func isAllowSpace(r rune) bool {  return !unicode.IsSpace(r) && !unicode.IsPunct(r) }

這樣可以在 TotalWords 函數開頭增加 AutoSpace 進行規范化。這時結果就正常了。

處理標點和其他類型

以上例子標點沒計算在內,而且如果英文和中文標點混合在一起,情況又復雜了。

為了更好地實現開始的需求分析,重構以上代碼,設計如下的結構:

type Counter struct {  Total     int // 總字數 = Words + Puncts  Words     int // 只包含字符數  Puncts    int // 標點數  Links     int // 鏈接數  Pics      int // 圖片數  CodeLines int // 代碼行數 }

同時將 TotalWords 重構為 Counter 的 Stat 方法,同時記錄標點數:

func (wc *Counter) Stat(str string) {  wc.Links = len(rxStrict.FindAllString(str, -1))  wc.Pics = len(imgReg.FindAllString(str, -1))   // 剔除 HTML  str = StripHTML(str)   str = AutoSpace(str)   // 普通的鏈接去除(非 HTML 標簽鏈接)  str = rxStrict.ReplaceAllString(str, " ")  plainWords := strings.Fields(str)   for _, plainWord := range plainWords {   words := strings.FieldsFunc(plainWord, func(r rune) bool {    if unicode.IsPunct(r) {     wc.Puncts++     return true    }    return false   })    for _, word := range words {    runeCount := utf8.RuneCountInString(word)    if len(word) == runeCount {     wc.Words++    } else {     wc.Words += runeCount    }   }  }   wc.Total = wc.Words + wc.Puncts }  var (  rxStrict = xurls.Strict()  imgReg   = regexp.MustCompile(`<img [^>]*>`)  stripHTMLReplacer = strings.NewReplacer("\n", " ", "</p>", "\n", "<br>", "\n", "<br />", "\n") )  // StripHTML accepts a string, strips out all HTML tags and returns it. func StripHTML(s string) string {  // Shortcut strings with no tags in them  if !strings.ContainsAny(s, "<>") {   return s  }  s = stripHTMLReplacer.Replace(s)   // Walk through the string removing all tags  b := GetBuffer()  defer PutBuffer(b)  var inTag, isSpace, wasSpace bool  for _, r := range s {   if !inTag {    isSpace = false   }    switch {   case r == '<':    inTag = true   case r == '>':    inTag = false   case unicode.IsSpace(r):    isSpace = true    fallthrough   default:    if !inTag && (!isSpace || (isSpace && !wasSpace)) {     b.WriteRune(r)    }   }    wasSpace = isSpace   }  return b.String() }

代碼過多的細節不討論。此外,關于文章內的代碼行數統計未實現(目前沒有想到特別好的方法,如果你有,歡迎交流)。

感謝各位的閱讀!關于“Go怎么實現精準統計文章字數”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

go
AI

青冈县| 汽车| 天水市| 白城市| 陇西县| 藁城市| 广饶县| 长沙市| 武城县| 鄂尔多斯市| 梁山县| 宿州市| 肃南| 剑川县| 翁源县| 东台市| 台北县| 福安市| 霍城县| 凌云县| 太仆寺旗| 兰溪市| 莱西市| 星子县| 宁国市| 阿拉善盟| 长春市| 平定县| 边坝县| 福泉市| 蒙阴县| 阿城市| 同德县| 松潘县| 乳山市| 财经| 上思县| 双城市| 汉源县| 平湖市| 康定县|