此文件內容為飛書文件複製過來作為搜索,存在內容格式不相容情況,建議看原飛書文件
背景#
作為時常在推特發布推文的免費使用者,經常會遇到在想要發布稍微長一點的內容的時候,就會碰到推特推文的限制。
此時你就需要手動對內容進行切割,並且為了讓切割後的推文內容能更加清晰,通常會在前面增加類似 "(x/x)" 的前綴來說明推文切割內容的進度。如果在編輯的過程中,你又想要增加一些新的內容,就容易遇到重新調整推文分割的情況。所以在遇到這個場景越來越多的時候,我就想著做一個針對該場景的腳本來幫助我自動做這件事情。
這篇文章會簡單描述下在寫該腳本的一些過程和設計,雖然腳本實現難度並不大,但也主要是想作為輸出者,對後續自己所開發的專案,通過輸出博客,來進行專案的反思和沉澱,同時也希望能幫助到有類似需求的人。
repo 地址:https://github.com/catwithtudou/x_tool
需求功能#
一句話描述功能:輸入一段排版後的文字,若超過推特推文的長度限制則自動進行切割,並增加切割進度前綴信息。
這裡需要注意的是:
- 在切割的過程中需要滿足,不能調整原文的排版內容,且盡可能多地填充一次推文的內容
- 需要支援中文相關字符的處理,切割後避免出現因中文字符長度特殊而導致的亂碼
關鍵設計#
推文長度限制#
首先就需要了解目前推特推文的長度限制,從而方便後續的字符長度計算:
- 長度限制為 280 個字符,不包括鏈接和圖片
- 對於中文字符是按兩個字符來計算,其餘字符(包含標點符號、空格、換行等)是按一個字符來計算
Go 中的字符長度計算#
這裡我們需要了解一些 Go 中的前置信息:
- 字串默認都是以 UTF-8 編碼保存的,其中每個中文佔用 3 個字節
- 可通過 rune 數據類型數組來保存字串,其中 rune 類型即 Unicode 編碼,而每個中文則佔用一個長度
所以根據以上信息我們可以通過以下代碼計算出字串在推特推文中的字符長度:
func calculateTwitterContentLen(content string) int {
// utf8.RuneCountInString 方法可獲得字串轉成 rune 數組的長度
runeCount := utf8.RuneCountInString(content)
return runeCount + (len(content)-runeCount)/2
}
二分查找字符截斷位置#
若推文內容超過限制長度,根據其限制長度找到目前字串中第一個長度為限制長度的子字串。需要注意:
- 這裡所指的長度是 "推文中的字符長度"
- 在查詢字符截斷位置之前,需要算上前綴進度(如 "(1/2)")字符的長度
- 在進行截斷的時候,避免出現因中文字符字節不完全導致中文亂碼的情況
為了提高查找的性能,這裡採用二分查詢去找到字串中第一個滿足推文長度限制的位置,所以代碼如下:
// splitFirstMaxTwitterContent 查找到對應第一個截斷位置後輸出切割後的左右字串
func splitFirstMaxTwitterContent(content string) (left string, right string) {
contentLen := len(content)
if contentLen <= twitterMaxLength {
return content, ""
}
// 可以看到這裡計算長度都是按 Unicode 的方式去查找,避免出現中文亂碼
runeContent := []rune(content)
runeIdx := sort.Search(len(runeContent), func(i int) bool {
_, isExceed := calculateTwitterRuneContentLen(runeContent[:i])
return isExceed
})
return string(runeContent[:runeIdx]), string(runeContent[runeIdx:])
}
func calculateTwitterRuneContentLen(runeContent []rune) (int, bool) {
tweetLen := len(runeContent) + (len(string(runeContent))-len(runeContent))/2
return tweetLen, tweetLen >= twitterMaxLength
}
使用說明#
- 執行編譯好的 main 程序
- 根據終端的提示輸入想要發布的推文內容,輸入完畢後換行輸入 "exit" 標識結束
- 最後若推文內容沒有超過限制長度則返回原文,若有超過,程序會輸出自動截斷後的推文內容並加上前綴進度
./main
===================================================
Please enter the content of the tweet (finally enter "exit" to end the input):
這會是一條測試文案:以下語句摘自《正見》
潛意識中,我們期待自己會到達不再需要修理任何東西的境界。總有一天,我們會「從此過著快樂的生活」。我們深信「解決」的概念。好像我們所有經歷的一切,到這一刻為止的生命,都只是在彩排。盛大的演出還沒開始。對大多數的人來說,這種永無休止的處理
exit
===================================================
Current Tweet Length: 566
Exceed the Twitter length limit: true
===================================================
Now back to the cut tweet content
>>>>>>>「the 1th tweet content」
(1/3)這會是一條測試文案:以下語句摘自《正見》
潛意識中,我們期待自己會到達不再需要修理任何東西的境界。總有一天,我們會「從此過著快樂的生活」。我們深信「解決」的概念。好像我們所有經歷的一切,到這一刻為止的生命,都只是在彩排。盛大的演出還沒開始。對大多數的人來說,這種永無休止的處理
>>>>>>>「the 2th tweet content」
(2/3)和重新安排以及更新版本,就是生活的定義。事實上,我們是在等待生命開始。
我們往往也會這麼想:當我們死後,世界依然存在。同樣的太陽會繼續照亮大地,同樣的星球會繼續轉動,因為我們認為從開天闢地以來,它們一直都是如此。我們的孩子會繼承這個地球。這都顯示出我們對於不斷流轉的世間和一切現象是多麼無知。
>>>>>>>「the 3th tweet content」
(3/3)現象是多麼無知。
>>>>>>>「End of tweet cutting」
後續拓展#
- 終端交互優化
- 自動發布推文
- 排版優化
- .....