放課後プログラミング

調べたことや考えたことなどを忘れないために書きます。

java.lang.String#trim()は全角スペースを消してくれない

java.lang.String#trim()javadocには(拙訳)

1. 空文字列もしくは最初と最後が\u0020より大きい文字ならそのオブジェクトをそのまま返す
2. それ以外の場合、\u0020以下の文字しか存在しない文字列なら新しい空文字列オブジェクトを返す
3. それ以外の場合、最初の\u0020以下ではない文字のインデックスをk、最後の\u0020以下ではない文字のインデックスをmとしたとき、this.substring(k, m+1)の結果を返す

とあります。
\u0020以下とはすなわち制御文字と半角スペースのことで、全角スペースを消すような仕様はありません。

なので自分用にtrim()を実装し直しました。

元々のjava.lang.String#trim()

public String trim() {
    int len = value.length;
    int st = 0;
    char[] val = value;    /* avoid getfield opcode */

    while ((st < len) && (val[st] <= ' ')) {
        st++;
    }
    while ((st < len) && (val[len - 1] <= ' ')) {
        len--;
    }
    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}

staticメソッドとして書き換えたバージョン

class StringUtils {
    /**
     * also trims 2byte space chars.
     *
     * @see java.lang.String#trim()
     * this won't trim 2 byte space chars.
     */
    public static String trim(String value) {
        if (value == null) {
            return null;
        }
        int len = value.length();
        int st = 0;
        char[] val = value.toCharArray();

        while ((st < len) && (val[st] <= ' ' || val[st] == ' ')) {
            st++;
        }
        while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == ' ')) {
            len--;
        }
        return ((st > 0) || (len < value.length())) ? value.substring(st, len) : value;
    }
}
public class StringUtilsTest {

    @Test // = OK
    public void testTrim_前後の空白を取り除く() throws Exception {
        //exercise
        String actual = CStringUtils.trim(" hoge ");
        //assertion
        assertThat(actual, is("hoge"));
    }

    @Test // = OK
    public void testTrim_前後の全角空白を取り除く() throws Exception {
        //exercise
        String actual = CStringUtils.trim(" hoge ");
        //assertion
        assertThat(actual, is("hoge"));
    }
}

適宜whileの条件に自分が消したい文字を追加していけば自分の好きな仕様のtrim()が実装できますね。