1. 序章

この短いチュートリアルでは、文字列から先頭と末尾の文字を削除するいくつかの方法を説明します。 簡単にするために、例ではゼロを削除します。

実装ごとに、2つのメソッドを作成します。1つは先頭のゼロ用、もう1つは末尾のゼロ用です。

この問題にはエッジケースがあります。入力にゼロのみが含まれている場合、どうすればよいでしょうか。 空のString、または単一のゼロを含む String を返しますか? それぞれのソリューションで、両方のユースケースの実装を確認します。

実装ごとに単体テストがあり、GitHubを見つけることができます。

2. StringBuilderを使用する

最初のソリューションでは、元の文字列を使用して StringBuilderを作成し、不要な文字を最初または最後から削除します。

String removeLeadingZeroes(String s) {
    StringBuilder sb = new StringBuilder(s);
    while (sb.length() > 0 && sb.charAt(0) == '0') {
        sb.deleteCharAt(0);
    }
    return sb.toString();
}

String removeTrailingZeroes(String s) {
    StringBuilder sb = new StringBuilder(s);
    while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '0') {
        sb.setLength(sb.length() - 1);
    }
    return sb.toString();
}

末尾のゼロを削除するときは、 StringBuilder.deleteCharAt()の代わりに StringBuilder.setLength()を使用することに注意してください。これは、最後の数文字も削除し、パフォーマンスが向上するためです。

入力にゼロのみが含まれているときに空の文字列を返したくない場合は、ループを停止して文字が1つだけ残っている場合にのみ実行する必要があります。

したがって、ループ条件を変更します。

String removeLeadingZeroes(String s) {
    StringBuilder sb = new StringBuilder(s);
    while (sb.length() > 1 && sb.charAt(0) == '0') {
        sb.deleteCharAt(0);
    }
    return sb.toString();
}

String removeTrailingZeroes(String s) {
    StringBuilder sb = new StringBuilder(s);
    while (sb.length() > 1 && sb.charAt(sb.length() - 1) == '0') {
        sb.setLength(sb.length() - 1);
    }
    return sb.toString();
}

3. String.subString()を使用する

このソリューションでは、先頭または末尾のゼロを削除すると、 最初または最後のゼロ以外の文字の位置を見つけます。

その後、 substring()を呼び出すだけで、残りの部分が返されます。

String removeLeadingZeroes(String s) {
    int index;
    for (index = 0; index < s.length(); index++) {
        if (s.charAt(index) != '0') {
            break;
        }
    }
    return s.substring(index);
}

String removeTrailingZeroes(String s) {
    int index;
    for (index = s.length() - 1; index >= 0; index--) {
        if (s.charAt(index) != '0') {
            break;
        }
    }
    return s.substring(0, index + 1);
}

ループのスコープ外で変数を使用するため、forループの前に変数indexを宣言する必要があることに注意してください。

また、 String.indexOf() String.lastIndexOf()は完全一致に対してのみ機能するため、ゼロ以外の文字を手動で検索する必要があることに注意してください。

空の文字列を返したくない場合は、前と同じことを行う必要があります。ループ条件を変更する

String removeLeadingZeroes(String s) {
    int index;
    for (index = 0; index < s.length() - 1; index++) {
        if (s.charAt(index) != '0') {
            break;
        }
    }
    return s.substring(index);
}

String removeTrailingZeroes(String s) {
    int index;
    for (index = s.length() - 1; index > 0; index--) {
        if (s.charAt(index) != '0') {
            break;
        }
    }
    return s.substring(0, index + 1);
}

4. ApacheCommonsの使用

Apache Commonsには、org.apache.commons.lang.StringUtilsを含む多くの便利なクラスがあります。 より正確には、このクラスはApacheCommonsLang3にあります。

4.1. 依存関係

この依存関係をpom.xmlファイルに挿入することで、 Apache CommonsLang3を使用できます。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

4.2. 実装

StringUtils クラスには、メソッド stripStart()および stripEnd()があります。 それぞれ先頭と末尾の文字を削除します。

それがまさに私たちが必要としているものなので、私たちのソリューションは非常に簡単です。

String removeLeadingZeroes(String s) {
    return StringUtils.stripStart(s, "0");
}

String removeTrailingZeroes(String s) {
    return StringUtils.stripEnd(s, "0");
}

残念ながら、すべてのオカレンスを削除するかどうかを設定することはできません。 したがって、手動で制御する必要があります。

入力が空ではなく、削除された String が空の場合、正確に1つのゼロを返す必要があります。

String removeLeadingZeroes(String s) {
    String stripped = StringUtils.stripStart(s, "0");
    if (stripped.isEmpty() && !s.isEmpty()) {
        return "0";
    }
    return stripped;
}

String removeTrailingZeroes(String s) {
    String stripped = StringUtils.stripEnd(s, "0");
    if (stripped.isEmpty() && !s.isEmpty()) {
        return "0";
    }
    return stripped;
}

これらのメソッドは、2番目のパラメーターとしてStringを受け入れることに注意してください。 このStringは、削除するシーケンスではなく、文字のセットを表します。

たとえば、“ 01” を渡すと、‘0’または‘1’の先頭または末尾の文字がすべて削除されます。

5. グアバの使用

Guavaは多くのユーティリティクラスも提供しています。 この問題には、 com.google.common.base.CharMatcher を使用できます。これは、一致する文字と対話するためのユーティリティメソッドを提供します。

5.1. 依存関係

Guavaを使用するには、次の依存関係pom.xmlファイルに追加する必要があります。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

AndroidアプリケーションでGuavaを使用する場合は、代わりにバージョン27.0-androidを使用する必要があることに注意してください。

5.2. 実装

この例では、 trimLeadingFrom() trimTrailingFrom()に関心があります。

名前が示すように、 String からそれぞれ先頭または末尾の文字を削除します。これは、CharMatcherと一致します。

String removeLeadingZeroes(String s) {
    return CharMatcher.is('0').trimLeadingFrom(s);
}

String removeTrailingZeroes(String s) {
    return CharMatcher.is('0').trimTrailingFrom(s);
}

それらは、私たちが見たApacheCommonsメソッドと同じ特性を持っています。

したがって、すべてのゼロを削除したくない場合は、同じトリックを使用できます。

String removeLeadingZeroes(String s) {
    String stripped = CharMatcher.is('0').trimLeadingFrom(s);
    if (stripped.isEmpty() && !s.isEmpty()) {
        return "0";
    }
    return stripped;
}

String removeTrailingZeroes(String s) {
    String stripped = CharMatcher.is('0').trimTrailingFrom(s);
    if (stripped.isEmpty() && !s.isEmpty()) {
        return "0";
    }
    return stripped;
}

CharMatcher を使用すると、より複雑なマッチングルールを作成できることに注意してください。

6. 正規表現の使用

この問題はパターンマッチングの問題であるため、正規表現を使用できます。 Stringの最初または最後のですべてのゼロを一致させます。

その上、一致するゼロを削除したいと思います。 つまり、何も置き換えない、つまり空の文字列に置き換えます。

String.replaceAll()メソッドを使用すると、まさにそれを実行できます。

String removeLeadingZeroes(String s) {
    return s.replaceAll("^0+", "");
}

String removeTrailingZeroes(String s) {
    return s.replaceAll("0+$", "");
}

すべてのゼロを削除したくない場合は、ApacheCommonsとGuavaで使用したのと同じソリューションを使用できます。 ただし、これを行うための純粋な正規表現の方法があります。String全体と一致しないパターンを提供する必要があります。

そうすれば、入力にゼロのみが含まれている場合、正規表現エンジンは一致から正確に1つを除外します。 これは、次のパターンで実行できます。

String removeLeadingZeroes(String s) {
    return s.replaceAll("^0+(?!$)", "");
}

String removeTrailingZeroes(String s) {
    return s.replaceAll("(?!^)0+$", "");
}

“(?!^)” “(?!$)” は、それぞれStringの始まりでも終わりでもないことを意味します。

7. 結論

このチュートリアルでは、Stringから先頭と末尾の文字を削除するいくつかの方法を見ました。 これらの実装間の選択は、多くの場合、単に個人的な好みです。

いつものように、例はGitHubから入手できます。