小ネタ:Javaのsplitメソッドの引数に空文字指定すると1文字ずつ処理するんだね

Java

はじめに

文字列を一文字ずつ解析して何か処理する時に、for文を使わずに処理できないのかなぁと調べていたらsplitに行きつきました。サンプルコードも交えて記事にしています。

実行環境

開発環境

Visual Studio Code + Java + Windows環境で実行しています。

開発環境の構築は、以下の記事を基に作成しています。

Visual Studio CodeでJavaを書いて動かす【for Windows】
Javaの試験(Java Bronze, Java Silver)の学習をする際に、コマンドラインを使った学習が取り組みにくく感じるので、Visual Studio Code(以降、VS Codeとする)を使って環境構築からコードを書くところまでを記事にしました。

バージョンについて

以降で記載しているサンプルコードは、Java 11を使って確認しています。

実行方法

文字列を1文字ずつバラバラにするには、splitメソッドの引数に空文字を指定すればよいです

サンプルコード

public class SplitSample {
  public static void main(String[] args) {

    final String SPLIT_STRING = "HELLO";
    String[] array = SPLIT_STRING.split("");
    for (String s : array) {
      System.out.println(s);
    }
  }
}

ポイント

5行目:splitメソッドの引数に空文字を指定しています。これで、変数arrayには”HELLO”が1文字ずつに分割された配列が設定されます。

出力結果

手元の実行環境で動かした結果です。

ターミナル内容

PS C:\JavaWorkspace> javac -encoding UTF-8 SplitSample.java
PS C:\JavaWorkspace> java "-Dfile.encoding=UTF-8" SplitSample
H
E
L
L
O

一文字ずつ出力されていることがわかりますね。

目的のコードに近づける

さて、上のサンプルコードだと結局拡張for文を使っているので、目的のコードに近づけます。サンプルコードでは結果を分かりやすくするためにprintln()を使用しましたが、実際の結果に欲しかったのは

“HHEELLLLOO”

という文字列だったので、この文字列を作ります。

注意

この項のコードはStreamを利用してプログラムコードを作成しています。

サンプルコード

import java.util.*;
import java.util.stream.*;

public class SplitSample {
  public static void main(String[] args) {
    final String SPLIT_STRING = "HELLO";
    String str = Arrays.stream(SPLIT_STRING.split(""))
                       .map(s -> s.repeat(2))
                       .collect(Collectors.joining()));
    System.out.println(str);
  }
}

ポイント

7行目:Arraysクラスを使ってsplitの結果をstreamに変換する。

8行目:それぞれの文字を2文字ずつにする。(stream.map()を使用)

9行目:collectでstreamの要素を連結する。(Collectors.joining()を使用し、区切り文字無しで連結)

10行目:連結した文字列を表示しておしまい。

出力結果

PS C:\JavaWorkspace> javac -encoding UTF-8 SplitSample.java
PS C:\JavaWorkspace> java "-Dfile.encoding=UTF-8" SplitSample
HHEELLLLOO

for文を使わずに、意図した結果の文字列が表示されました。

おまけ

splitを使わずにfor文を使って書いたコードが、以下のサンプルコードです。

サンプルコード(for文)

public class SplitSample {
  public static void main(String[] args) {

    final String SPLIT_STRING = "HELLO";
    String[] forArray = new String[SPLIT_STRING.length()];

    for (int i = 0; i < SPLIT_STRING.length(); i++) {
      forArray[i] = String.valueOf(SPLIT_STRING.charAt(i)).repeat(2);
    }
    for (String s : forArray) {
      System.out.print(s);
    }
    System.out.println(s);

  }
}

5行目:配列用の変数を用意します。1文字ずつ分割するので、配列長 = 文字列長となります。

8行目:要素位置にあたる文字をStringに変換して、repeatメソッドで文字を2つにします。

10行目~:配列要素を順次出力し、13行目で改行のみ出力しています。

おまけを書いた感想

StreamなどがないJava7以前の環境だと、こういう風に書くのかなぁと思いながら書いてました。

最後に

この挙動、特にJavadocとかに書かれてるわけでもないですが、知っている人も結構見かける割と知られていそうな小ネタでした。

ただ、正規表現を調べてみても、空文字指定したときの挙動がどうにも見つからないので、実際のところはどういう仕様で動くものなのだろうか。

ちなみにPatternクラスや、Matcherクラスのfindメソッドとかも眺めてみたのですが、途中で追うのがしんどくなったのでやめました。。。Patternクラスの生成時、空文字がpatternに指定された場合の分岐もあるから、その辺の考慮も含めて実装されているんだなぁと思いました。

コメント

タイトルとURLをコピーしました