Javaで文字列を特定の文字数で区切って、配列に入れる

例えばツイッターでbotなんかを作る時、文字数を確認しないとツイートする文字がはみ出てしまうかもしれない。
140文字で区切って、(続く)と表示して次のツイートを表示させたいときもあると思う。

そのためには文字列を編集しなければいけない。
300文字のツイートがあれば、
140文字、140文字、20文字で3回に分けてツイートできるように、まずは文字列を適当に分割したり、文の最後に特定の文字列を追記する(「続く」とか入れるために)ための機能を作ってみた。

まずはインターフェースから。
twitterのbotに限らず、文字列を編集したいときに使えるように抽象化した(あんまりできていないけど)

package twitter.util;
import java.util.List;
public interface Editor {
/** 文章を分割する*/
public List separate(String separator,String sentence);
/** 文字数をカウントします */
public int wordCount(String sentence);
/** 140字に分割したリストで返します */
public List split140Chars(String sentence);
/** 指定した文字数に分割したリストで返します */
public List splitChars(int numOfChar , String sentence);
/** 指定した文字数に分割し、各々の末尾に指定の文字を追記します */
public List splitCharsWithSuffics(int numOfChar,String sentence,String suffics);
}

で、これを実装したクラスは以下の通り。
特定の文字数で区切るのに苦戦した。。勉強を続けていくうちにもっと良いアルゴリズムがわかると思うので、そのときにまた改良する。

package twitter.util;
import java.util.ArrayList;
import java.util.List;
public class TweetEditor implements Editor{
public List separate(String separator, String tweet ) {
List<String> tweetList = new ArrayList<String>();
String tweetArray[] = tweet.split(separator,0);
for(int i = 0; i <  tweetArray.length; i++) {
tweetList.add(tweetArray[i]);
}
return tweetList;
}
public int wordCount(String tweet) {
int wordCnt = tweet.length();
return wordCnt;
}
public List split140Chars(String tweet) {
int charNum = 140;
List<String> tweetList = new ArrayList<String>();
char[] charArray = tweet.toCharArray();
StringBuilder splitTweet = new StringBuilder();
for(int i = 0; i < charArray.length; i++) {
splitTweet.append(charArray[i]);
//140文字で区切るロジックを通すための苦肉の策
int j = i;
//iは「0」から。しかし文字数は「1」から数えるため。整合性を合わせるために1を加える
j = j + 1;
//最後の判定は、iが1や2の場合、1÷140が0.0000・・・になって、丸められてしまうため。
if (!"".equals(splitTweet) && i != 0 && j % charNum == 0 && i >= charNum -1) {
tweetList.add(splitTweet.toString());
splitTweet.delete(0,splitTweet.length());
} else if(!"".equals(splitTweet) && i + 1 == charArray.length) {
tweetList.add(splitTweet.toString());
}
}
return tweetList;
}
public List splitChars(int numOfChar, String tweet) {
//基本的にはsplit140Chars()メソッドと同じロジック
int charNum = numOfChar;
List<String> tweetList = new ArrayList<String>();
char[] charArray = tweet.toCharArray();
StringBuilder splitTweet = new StringBuilder();
for(int i = 0; i < charArray.length; i++) {
splitTweet.append(charArray[i]);
int j = i;
j = j + 1;
if (!"".equals(splitTweet) && i != 0 && j % charNum == 0 && i >= charNum -1) {
tweetList.add(splitTweet.toString());
splitTweet.delete(0,splitTweet.length());
} else if(!"".equals(splitTweet) && i + 1 == charArray.length) {
tweetList.add(splitTweet.toString());
}
}
return tweetList;
}
public List splitCharsWithSuffics(int numOfChar, String tweet,String suffics) {
//末尾に「次へ」とか追記するときに使う
int charNum = numOfChar;
List<String> tweetList = new ArrayList<String>();
char[] charArray = tweet.toCharArray();
StringBuilder splitTweet = new StringBuilder();
for(int i = 0; i < charArray.length; i++) {
splitTweet.append(charArray[i]);
int j = i;
j = j + 1;
if (!"".equals(splitTweet) && i != 0 && j % charNum == 0 && i >= charNum -1) {
//ひと区切りで「続く」などのsufficsを挿入
splitTweet.append(suffics);
tweetList.add(splitTweet.toString());
splitTweet.delete(0,splitTweet.length());
} else if(!"".equals(splitTweet) && i + 1 == charArray.length) {
//こっちにはsufficsいらない
tweetList.add(splitTweet.toString());
}
}
return tweetList;
}
}

では、上記のクラスを使ってみる。

package twitter.util;
import java.util.ArrayList;
import java.util.List;
public class MainTest {
public static void main(String[] args) {
String sentence = "ありがとう。さようなら。またあう日まで";
List<String> sepList = new ArrayList<String>();
Editor edit = new TweetEditor();
sepList = edit.separate("。", sentence);
for (String s : sepList) {
System.out.println(s);
}
System.out.println("-----------------------------");
//250文字くらいの文章
String sentence2 = "研修をやってわかったことは、自分にはデータベース設計の経験が不足しているということだ。 " +
"既存のシステムの保守をやっていると、自分で設計する機会があまり無い。" +
"また、データベース設計はシステムの肝となる部分なので、若手のうちはあまり任せてもらえない可能性も高い。" +
"そんな経験を補うために、まずは基礎をしっかり固めて、自分で業務外の時間でデータベース設計を経験したいと考えた。" +
"まずは基礎をちゃんと固めることから、という意味も込めて「達人に学ぶDB設計徹底指南書」という本を購入した。";
List<String> sepList2 = new ArrayList<String>();
sepList2 = edit.split140Chars(sentence2);
for (String str : sepList2) {
System.out.println(str);
}
System.out.println("-------------------------------");
//100文字で区切ってみる
List<String> sepList3 = new ArrayList<String>();
sepList3 = edit.splitChars(100,sentence2);
for (String str : sepList3) {
System.out.println(str);
}
System.out.println("-------------------------------");
//120文字で区切って、末尾に「続く」をつけてみる
List<String> sepList4 = new ArrayList<String>();
sepList4 = edit.splitCharsWithSuffics(120,sentence2,"(続く)");
for (String str : sepList4) {
System.out.println(str);
}
}
}

出力結果は以下の通り

ありがとう
さようなら
またあう日まで
-----------------------------
研修をやってわかったことは、自分にはデータベース設計の経験が不足しているということだ。 既存のシステムの保守をやっていると、自分で設計する機会があまり無い。また、データベース設計はシステムの肝となる部分なので、若手のうちはあまり任せてもらえない可能性も高い。そんな経験を補うために
、まずは基礎をしっかり固めて、自分で業務外の時間でデータベース設計を経験したいと考えた。まずは基礎をちゃんと固めることから、という意味も込めて「達人に学ぶDB設計徹底指南書」という本を購入した。
-------------------------------
研修をやってわかったことは、自分にはデータベース設計の経験が不足しているということだ。 既存のシステムの保守をやっていると、自分で設計する機会があまり無い。また、データベース設計はシステムの肝となる部
分なので、若手のうちはあまり任せてもらえない可能性も高い。そんな経験を補うために、まずは基礎をしっかり固めて、自分で業務外の時間でデータベース設計を経験したいと考えた。まずは基礎をちゃんと固めることか
ら、という意味も込めて「達人に学ぶDB設計徹底指南書」という本を購入した。
-------------------------------
研修をやってわかったことは、自分にはデータベース設計の経験が不足しているということだ。 既存のシステムの保守をやっていると、自分で設計する機会があまり無い。また、データベース設計はシステムの肝となる部分なので、若手のうちはあまり任せてもらえ(続く)
ない可能性も高い。そんな経験を補うために、まずは基礎をしっかり固めて、自分で業務外の時間でデータベース設計を経験したいと考えた。まずは基礎をちゃんと固めることから、という意味も込めて「達人に学ぶDB設計徹底指南書」という本を購入した。

ちゃんと指定の文字数で文字列を分割することができた。
文字列を区切ってListに入れる機能まで作れば、あとはリストを回してtweetする機能を実装すれば、連続ツイートが可能になる。

ツイートしたい文章をDBなどに入れておきさえすれば、後は文字数を意識することなく好きな文章を書いておける。botが勝手に文章を区切ってくれるようになる。

それにしても、文字数判定に手こずり、けっこう時間がかかってしまった・・・。
でも楽しかった。色々とプログラムしながら悩んでいる時間が楽しくて仕方がない。
時間を忘れて夢中になれる。こういうのが仕事だったら毎日楽しいのかもしれない。今も十分幸せな環境だけど、存分にプログラムが書ける環境での仕事もしてみたいなぁ。

・・・肩が凝ったのでマッサージいってきます。