このドキュメントの内容は、検索用にコピーした Feishu ドキュメントです。コンテンツのフォーマットの互換性の問題がありますので、元のFeishu ドキュメントを参照することをお勧めします。
背景#
無料ユーザーとしてよくツイッターでツイートを投稿することがありますが、少し長いコンテンツを投稿しようとすると、ツイッターのツイート制限に遭遇することがよくあります。
その場合、コンテンツを手動で分割する必要があります。また、分割されたツイートの内容をより明確にするために、通常、ツイートの分割の進捗を示すために、"(x/x)" のような接頭辞を前に追加します。編集中に新しいコンテンツを追加したい場合、ツイートの分割を再調整する必要があることがよくあります。そのため、このようなシナリオに遭遇する頻度が増えるにつれて、このシナリオに対応するスクリプトを自動的に作成することを考えました。
この記事では、このスクリプトの開発プロセスと設計について簡単に説明します。スクリプトの実装はそれほど難しくありませんが、主に出力者として、後続の開発プロジェクトについて、ブログを通じて出力し、プロジェクトの反省と蓄積を行い、同様のニーズを持つ人々にも役立てることを目指しています。
リポジトリの場所:https://github.com/catwithtudou/x_tool
要件機能#
機能の要約:整形されたテキストを入力すると、ツイッターの文字制限を超える場合は自動的に分割し、分割の進捗情報を追加します。
以下に注意してください:
- 分割の過程で、元のテキストのレイアウトを変更せず、できるだけ多くのツイートのコンテンツを埋める必要があります。
- 中国語関連の文字の処理をサポートし、分割後に特殊な中国語文字の長さによる文字化けを回避します。
主要な設計#
ツイートの文字制限#
まず、現在のツイッターの文字制限を理解する必要があります。これにより、後続の文字の長さの計算が容易になります。
- 制限は 280 文字で、リンクや画像は含まれません。
- 中国語の文字は 2 文字としてカウントされ、その他の文字(句読点、スペース、改行などを含む)は 1 文字としてカウントされます。
Go での文字の長さの計算#
ここで、いくつかの Go の前提条件について理解する必要があります。
- 文字列はデフォルトで UTF-8 エンコードで保存され、各中国語文字は 3 バイトを占有します。
- 文字列を保存するために rune データ型の配列を使用できます。rune 型は Unicode エンコードであり、各中国語文字は 1 つの長さを占有します。
したがって、上記の情報に基づいて、以下のコードを使用して文字列のツイッターでの文字数を計算できます。
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
===================================================
ツイートの内容を入力してください(最後に "exit" と入力して入力を終了します):
これはテストテキストです:以下の文は「正見」からの引用です。
無意識の中で、私たちは自分自身が何も修理する必要がない状態に到達することを期待しています。いつか「幸せな人生を送る」という状態になるでしょう。私たちは「解決」という概念を信じています。まるで私たちのすべての経験、この瞬間までの人生がリハーサルであるかのようです。大規模なパフォーマンスはまだ始まっていません。多くの人にとって、この終わりのない処理と再配置、およびバージョンアップが人生の定義です。
私たちはしばしば次のように考えることもあります:私たちが死んだ後も、世界は存在し続けます。同じ太陽が地球を照らし続け、同じ惑星が回り続けるでしょう。なぜなら、私たちは天地創造以来、それが常にそうであると考えているからです。私たちの子供たちはこの地球を受け継ぐでしょう。これは、私たちが絶えず変化する世界とすべての現象に対してどれほど無知であるかを示しています。
exit
===================================================
現在のツイートの長さ:566
ツイッターの文字制限を超えていますか:true
===================================================
今、切り捨てられたツイートの内容に戻ります
>>>>>>>「1番目のツイートの内容」
(1/3)これはテストテキストです:以下の文は「正見」からの引用です。
無意識の中で、私たちは自分自身が何も修理する必要がない状態に到達することを期待しています。いつか「幸せな人生を送る」という状態になるでしょう。私たちは「解決」という概念を信じています。まるで私たちのすべての経験、この瞬間までの人生がリハーサルであるかのようです。大規模なパフォーマンスはまだ始まっていません。多くの人にとって、この終わりのない処理
>>>>>>>「2番目のツイートの内容」
(2/3)と再配置、およびバージョンアップが人生の定義です。
私たちはしばしば次のように考えることもあります:私たちが死んだ後も、世界は存在し続けます。同じ太陽が地球を照らし続け、同じ惑星が回り続けるでしょう。なぜなら、私たちは天地創造以来、それが常にそうであると考えているからです。私たちの子供たちはこの地球を受け継ぐでしょう。これは、私たちが絶えず変化する世界とすべての現象に対してどれほど無知であるかを示しています。
>>>>>>>「3番目のツイートの内容」
(3/3)。
>>>>>>>「ツイートの切り捨て終了」
拡張機能#
- ターミナルのインタラクションの最適化
- ツイートの自動投稿
- レイアウトの最適化
- .....