Before Java 8空の文字列で分割する場合
String[] tokens = "abc".split("");
分割メカニズムは、|
でマークされた場所で分割します
|a|b|c|
これは、各文字の前後に空のスペース""
が存在するためです。結果として、最初にこの配列を生成します
["", "a", "b", "c", ""]
後で 末尾の空の文字列を削除 (limit
引数に明示的に負の値を指定しなかったため)、最終的に戻ります
["", "a", "b", "c"]
In Java 8分割メカニズムは変更されたようです。
"abc".split("")
["a", "b", "c"]
の代わりに["", "a", "b", "c"]
配列を取得するため、開始時に空の文字列も削除されるように見えます。しかし、この理論は失敗します
"abc".split("a")
開始時に空の文字列を含む配列を返します["", "bc"]
。
誰かがここで何が起こっているのか、Java 8?
String.split
(Pattern.split
を呼び出す)の動作は、Java 7とJava 8。
Java 7 と Java 8 のPattern.split
のドキュメントを比較すると、次の句が追加されていることがわかります。
入力シーケンスの先頭に正の幅の一致がある場合、結果の配列の先頭に空の先行部分文字列が含まれます。ただし、先頭の幅がゼロの一致では、このような空の先行部分文字列は生成されません。
同じ句が Java 7 と比較して、 Java 8 のString.split
にも追加されます。
Java 7およびJava 8.の参照実装のPattern.split
のコードを比較しましょう。コードはバージョン7u40のgrepcodeから取得されます。 -b43および8-b132。
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
Java 8に次のコードを追加すると、入力文字列の先頭にあるゼロ長の一致が除外されます。これにより、上記の動作が説明されます。
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
split
がバージョン間で一貫して動作し、Java 8)の動作と互換性があるようにするには:
(?!\A)
を追加し、元の正規表現を非キャプチャグループ(?:...)
(必要であれば)。(?!\A)
は、文字列が文字列の先頭で終わっていないことをチェックします。これは、文字列の先頭で一致が空の一致であることを意味します。
split
を下位互換にするための一般的な解決策はありません。Java 7以前、独自のカスタム実装を指すようにsplit
のすべてのインスタンスを置き換えること以外は。
これは split(String regex, limit)
のドキュメントで指定されています。
この文字列の先頭に正の幅の一致がある場合、結果の配列の先頭に空の先行部分文字列が含まれます。ただし、先頭の幅がゼロの一致では、このような空の先行部分文字列は生成されません。
"abc".split("")
では、先頭にゼロ幅の一致があるため、先頭の空の部分文字列は結果の配列に含まれません。
ただし、2番目のスニペットでは、"a"
正の幅の一致(この場合は1)があるため、空の先行部分文字列が期待どおりに含まれます。
(無関係なソースコードを削除)
split()
from Java 7 to Java 8。次のステートメントが追加されました。
この文字列の先頭に正の幅の一致がある場合、結果の配列の先頭に空の先行部分文字列が含まれます。 しかし、最初のゼロ幅のマッチはそのような空の先行部分文字列を決して生成しません。
(エンファシス鉱山)
空の文字列の分割は、先頭で幅がゼロの一致を生成するため、空の文字列は、上記の指定に従って、結果の配列の先頭に含まれません。対照的に、"a"
で分割する2番目の例では、文字列の先頭でpositive-widthが一致するため、実際には空の文字列が先頭に含まれます結果の配列の。