以下のコードの問題を指摘し、修正してください。
ただし、問題は複数あることもあれば、全くないこともあります。
import org.apache.commons.lang.StringUtils;
public class TemplateReader {
private String template;
private String[] templateLines;
public TemplateReader(String resourceName) {
this.template = readTemplate(resourceName);
this.templateLines = StringUtils.split(this.template, "\r\n");
テンプレートの本文全体を取得します。
@return
public String getTemplate() {
return this.template;
テンプレートを改行で分割した配列を取得します。<br>
空行も空文字列として、配列に含めます。
@return
public String[] getTemplateLines() {
return this.templateLines;
テンプレートのリソースを読み込みます。<br>
テンプレートが読み込めない場合には、空の文字列を返します。
@param resourceName
@return
protected String readTemplate(String resourceName) {
String result = null;
return result;
ファイル(リソース)読み込みを行い、その後に文字列操作を行なっています。
今週の1/27(水)に、関西
Java
エンジニアの会(関ジャバ)の勉強会を開催します。
今回は「T2
フレームワーク
」「Griffon」「
GWT
vs XWT」など、
まだちょっと手を出してない人が多そうな(隙間の?)ネタが中心になっているので
興味はあるけど、実物を見たことがない、という人にもオススメです。
http://kokucheese.com/event/index/1199/
まだ少しだけ残席があるので、ぜひ今からでも応募してくださいね!
また、関ジャバでは発表者も募集しています。
Java
に直接関係ないネタでも構いませんので、とにかく「話したい!」という想いのある人は、
メールでもコメントでも、
Twitter
でも何でも構わないので、ぜひ、声を掛けてください!
今回は、ライブラリの利用方法に誤りがあります。
this.templateLines = StringUtils.split(this.template, "\r\n");
splitに正規表現を使いたくない場合によく使うStringUtilsですが、
APIをきちんと確認しないと、思わぬ挙動に悩まされることがあります。
StringUtils#splitは、以下ような挙動になるのです。
空要素はスキップする(連続したセパレータは、一つのセパレータとみなす)
セパレータに指定された文字列の一文字ずつで分割する
今回の例では、テキストファイルを読み込み、空行も空文字列として扱うのですから
空要素をスキップされては困ります。
そのため、空要素をスキップしない「splitPreserveAllTokens」を利用する必要があります。
this.templateLines = StringUtils.splitPreserveAllTokens(this.template, "\r\n");
しかし、これでもまだ問題があります。
StringUtils#splitは、String#splitと違い、引数に指定されたセパレータを
それぞれ1文字ずつに分割し、それぞれをセパレータとして扱います。
要するに、第二引数の「\r\n」は「\r」と「\n」に分解され
「\r」で分割し、「\n」でも分割されてしまうわけです。
そうすると、たとえば
StringUtils.splitPreserveAllTokens("abc\r\ndef", "\r\n");
この結果は {"abc", "def"} ではなく {"abc", "", "def"} となるのです。
引数に指定したセパレータ文字列を、まとめて1つのセパレータとして扱いたい場合は、
「splitByWholeSeparatorPreserveAllTokens」メソッドを利用します。
this.templateLines = StringUtils.splitByWholeSeparatorPreserveAllTokens(this.template, "\r\n");
これで、期待通りの挙動になるはずです。
上の解答の対処で、少しだけ気になる所があります。
それは末尾の改行に関して、です。
テキストファイルを作成する際、末尾に改行を入れたり入れなかったりすることがありますが、
仮に末尾に改行が入っていた場合、その次の行は空行とみなすべきでしょうか、
それとも無視すべきでしょうか?
たとえば同じApache CommonsのFilesUtils#readLinesなどでは、
末尾の改行コードは無視するような挙動となっています。
(末尾に改行コードが連続していれば、そこまでの空行はきちんと保持されます)
無視するか、無視しないか、どちらが正解かは仕様次第でしょうけど
現実的には、末尾の改行は無視する方が妥当だと思います。
末尾の改行を削除するには、StringUtils#chompメソッドを使えば良いでしょう。
「\r\n」「\r」「\n」のいずれでも、末尾の改行を一つだけ削除してくれます。
それでは、今回の問題をおさらいしておきましょう。
StringUtils#splitは、第二引数を分解して1文字ずつのセパレータとして扱う
StringUtils#splitは、空の要素をスキップする
末尾の改行を削除する場合は、StringUtils#chompを使うと良い