Antes do Java 8, quando dividimos em strings vazias, como
String[] tokens = "abc".split("");
mecanismo de divisão seria dividido em locais marcados com |
|a|b|c|
porque o espaço vazio ""
existe antes e depois de cada personagem. Então, como resultado, ele geraria primeiro este array
["", "a", "b", "c", ""]
e mais tarde removerá strings vazias (porque não fornecemos explicitamente um valor negativo para o limit
argumento), então ele finalmente retornará
["", "a", "b", "c"]
No Java 8, o mecanismo de divisão parece ter mudado. Agora, quando usamos
"abc".split("")
obteremos ["a", "b", "c"]
array em vez de, ["", "a", "b", "c"]
então, parece que strings vazias no início também são removidas. Mas esta teoria falha porque, por exemplo
"abc".split("a")
retorna a matriz com uma string vazia no início ["", "bc"]
.
Alguém pode explicar o que está acontecendo aqui e como as regras de divisão mudaram no Java 8?
s.split("(?!^)")
parece funcionar.split("")
em vez de enigmática (para as pessoas que não usam regex)split("(?!^)")
ousplit("(?<!^)")
ou alguns outros regexes.Respostas:
O comportamento de
String.split
(que chamaPattern.split
) muda entre Java 7 e Java 8.Documentação
Comparando entre a documentação de
Pattern.split
em Java 7 e Java 8 , observamos a seguinte cláusula que está sendo adicionado:A mesma cláusula também é adicionada
String.split
no Java 8 , em comparação com o Java 7 .Implementação de referência
Vamos comparar o código da
Pattern.split
implementação de referência em Java 7 e Java 8. O código é recuperado de grepcode, para as versões 7u40-b43 e 8-b132.Java 7
Java 8
A adição do código a seguir em Java 8 exclui a correspondência de comprimento zero no início da string de entrada, o que explica o comportamento acima.
Manter a compatibilidade
Seguindo o comportamento no Java 8 e superior
Para tornar o
split
comportamento consistente entre as versões e compatível com o comportamento em Java 8:(?!\A)
no final da regex e envolver a regex original no grupo de não captura(?:...)
(se necessário).(?!\A)
verifica se a string não termina no início da string, o que implica que a correspondência é uma correspondência vazia no início da string.Seguindo o comportamento em Java 7 e anteriores
Não há uma solução geral para tornar
split
compatível com versões anteriores do Java 7 e anteriores, exceto substituir todas as instâncias desplit
para apontar para sua própria implementação customizada.fonte
split("")
código para que seja consistente nas diferentes versões de java?(?!^)
ao final do regex e envolvendo o regex original em um grupo de não captura(?:...)
(se necessário), mas não consigo pensar em nenhum maneira de torná-lo compatível com versões anteriores (siga o comportamento antigo em Java 7 e anteriores)."(?!^)"
? Em que cenários será diferente""
? (Eu sou péssimo em regex!: - /).Pattern.MULTILINE
bandeira, embora\A
sempre corresponda ao início da string, independentemente das bandeiras.Isso foi especificado na documentação de
split(String regex, limit)
.Em,
"abc".split("")
você obteve uma correspondência de largura zero no início, de modo que a substring vazia inicial não é incluída na matriz resultante.No entanto, em seu segundo snippet, ao dividir,
"a"
você obteve uma correspondência de largura positiva (1 neste caso), portanto, a substring inicial vazia é incluída conforme o esperado.(Código-fonte irrelevante removido)
fonte
Houve uma pequena mudança nos documentos
split()
de Java 7 para Java 8. Especificamente, a seguinte instrução foi adicionada:(ênfase minha)
A divisão da string vazia gera uma correspondência de largura zero no início, portanto, uma string vazia não é incluída no início da matriz resultante de acordo com o que é especificado acima. Por outro lado, seu segundo exemplo que se divide
"a"
gera uma correspondência de largura positiva no início da string, de modo que uma string vazia é de fato incluída no início do array resultante.fonte
"some-string".split("")
é um caso bastante raro..split("")
não é a única maneira de dividir sem combinar nada. Usamos uma regex lookahead positiva que em jdk7, que também correspondeu no início e produziu um elemento head vazio que agora se foi. github.com/spray/spray/commit/…