Como dividir a string "Thequickbrownfoxjumps"
em substrings de tamanho igual em Java. Por exemplo. "Thequickbrownfoxjumps"
de 4 tamanho igual deve dar a saída.
["Theq","uick","brow","nfox","jump","s"]
Pergunta semelhante:
Como dividir a string "Thequickbrownfoxjumps"
em substrings de tamanho igual em Java. Por exemplo. "Thequickbrownfoxjumps"
de 4 tamanho igual deve dar a saída.
["Theq","uick","brow","nfox","jump","s"]
Pergunta semelhante:
Respostas:
Aqui está a versão de uma linha do regex:
System.out.println(Arrays.toString(
"Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
\G
é uma asserção de largura zero que corresponde à posição em que a correspondência anterior terminou. Se não foi páreo anterior, que corresponde ao início da entrada, o mesmo que \A
. O lookbehind em anexo corresponde à posição de quatro caracteres desde o final da última partida.
Ambos olham para trás e \G
são recursos avançados de regex, não suportados por todos os tipos. Além disso, \G
não é implementado de forma consistente nos sabores que o suportam. Esse truque funcionará (por exemplo) em Java , Perl, .NET e JGSoft, mas não em PHP (PCRE), Ruby 1.9+ ou TextMate (ambos Oniguruma). O JavaScript /y
(sinalizador fixo) não é tão flexível quanto \G
, e não poderia ser usado dessa maneira, mesmo se o JS suportasse o lookback.
Devo mencionar que não recomendo necessariamente esta solução se você tiver outras opções. As soluções não regex nas outras respostas podem ser mais longas, mas também são auto-documentadas; este é exatamente o oposto disso. ;)
Além disso, isso não funciona no Android, que não suporta o uso de \G
lookbehinds.
String.substring()
em vez de um regex, mas exige algumas linhas extras de código, será executado em algum lugar na ordem de 5x mais rápido ...
(?s)
na expressão regular: (?s)(?<=\\G.{4})
.
java.util.regex.PatternSyntaxException: Look-behind pattern matches must have a bounded maximum length
Bem, é bastante fácil fazer isso com operações aritméticas e de cordas simples:
public static List<String> splitEqually(String text, int size) {
// Give the list the right capacity to start with. You could use an array
// instead if you wanted.
List<String> ret = new ArrayList<String>((text.length() + size - 1) / size);
for (int start = 0; start < text.length(); start += size) {
ret.add(text.substring(start, Math.min(text.length(), start + size)));
}
return ret;
}
Não acho que valha a pena usar um regex para isso.
EDIT: Meu raciocínio para não usar uma regex:
Splitter.fixedLength(4)
conforme sugerido pelo seanizer.
Isso é muito fácil com o Google Guava :
for(final String token :
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
Resultado:
Theq
uick
brow
nfox
jump
s
Ou, se você precisar do resultado como uma matriz, poderá usar este código:
String[] tokens =
Iterables.toArray(
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps"),
String.class
);
Referência:
Nota: A construção do divisor é mostrada em linha acima, mas como os divisores são imutáveis e reutilizáveis, é uma boa prática armazená-los em constantes:
private static final Splitter FOUR_LETTERS = Splitter.fixedLength(4);
// more code
for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
String.join(separator, arrayOrCollection)
Se você estiver usando as bibliotecas de uso geral de goiaba do Google (e, sinceramente, qualquer novo projeto Java provavelmente deveria ser), isso é incrivelmente trivial para a classe Splitter :
for (String substring : Splitter.fixedLength(4).split(inputString)) {
doSomethingWith(substring);
}
e é isso . Fácil como!
public static String[] split(String src, int len) {
String[] result = new String[(int)Math.ceil((double)src.length()/(double)len)];
for (int i=0; i<result.length; i++)
result[i] = src.substring(i*len, Math.min(src.length(), (i+1)*len));
return result;
}
src.length()
e len
são ambos int
s, sua ligação ceiling
não está cumprindo o que você deseja - confira como algumas das outras respostas estão fazendo: (src.length () + len - 1) / len
public String[] splitInParts(String s, int partLength)
{
int len = s.length();
// Number of parts
int nparts = (len + partLength - 1) / partLength;
String parts[] = new String[nparts];
// Break into parts
int offset= 0;
int i = 0;
while (i < nparts)
{
parts[i] = s.substring(offset, Math.min(offset + partLength, len));
offset += partLength;
i++;
}
return parts;
}
for
loops?
for
loop é realmente uma opção mais 'natural' para isso :-) Obrigado por apontar isso.
Você pode usar substring
from String.class
(manipulação de exceções) ou Apache lang commons (ele lida com exceções para você)
static String substring(String str, int start, int end)
Coloque-o dentro de um loop e você estará pronto.
substring
método na String
classe padrão ?
Prefiro esta solução simples:
String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
System.out.println(content.substring(0, 4));
content = content.substring(4);
}
System.out.println(content);
substring
implementação mudou com o Java 7, atualização 6, em meados de 2012, quando os campos offset
e count
foram removidos da String
classe. Portanto, a complexidade substring
tornou-se linear muito antes de essa resposta ser feita. Mas para uma sequência pequena como o exemplo, ela ainda é executada com rapidez suficiente e para sequências mais longas ... bem, essa tarefa raramente ocorre na prática.
Aqui está uma implementação de um liner usando fluxos Java8:
String input = "Thequickbrownfoxjumps";
final AtomicInteger atomicInteger = new AtomicInteger(0);
Collection<String> result = input.chars()
.mapToObj(c -> String.valueOf((char)c) )
.collect(Collectors.groupingBy(c -> atomicInteger.getAndIncrement() / 4
,Collectors.joining()))
.values();
Ele fornece a seguinte saída:
[Theq, uick, brow, nfox, jump, s]
String[] result = IntStream.range(0, (input.length()+3)/4) .mapToObj(i -> input.substring(i *= 4, Math.min(i + 4, input.length()))) .toArray(String[]::new);
Aqui está uma versão de uma linha que usa o Java 8 IntStream para determinar os índices do início da fatia:
String x = "Thequickbrownfoxjumps";
String[] result = IntStream
.iterate(0, i -> i + 4)
.limit((int) Math.ceil(x.length() / 4.0))
.mapToObj(i ->
x.substring(i, Math.min(i + 4, x.length())
)
.toArray(String[]::new);
Caso você queira dividir a string igualmente para trás, ou seja, da direita para a esquerda, por exemplo, para dividir 1010001111
em [10, 1000, 1111]
, aqui está o código:
/**
* @param s the string to be split
* @param subLen length of the equal-length substrings.
* @param backwards true if the splitting is from right to left, false otherwise
* @return an array of equal-length substrings
* @throws ArithmeticException: / by zero when subLen == 0
*/
public static String[] split(String s, int subLen, boolean backwards) {
assert s != null;
int groups = s.length() % subLen == 0 ? s.length() / subLen : s.length() / subLen + 1;
String[] strs = new String[groups];
if (backwards) {
for (int i = 0; i < groups; i++) {
int beginIndex = s.length() - subLen * (i + 1);
int endIndex = beginIndex + subLen;
if (beginIndex < 0)
beginIndex = 0;
strs[groups - i - 1] = s.substring(beginIndex, endIndex);
}
} else {
for (int i = 0; i < groups; i++) {
int beginIndex = subLen * i;
int endIndex = beginIndex + subLen;
if (endIndex > s.length())
endIndex = s.length();
strs[i] = s.substring(beginIndex, endIndex);
}
}
return strs;
}
eu uso a seguinte solução java 8:
public static List<String> splitString(final String string, final int chunkSize) {
final int numberOfChunks = (string.length() + chunkSize - 1) / chunkSize;
return IntStream.range(0, numberOfChunks)
.mapToObj(index -> string.substring(index * chunkSize, Math.min((index + 1) * chunkSize, string.length())))
.collect(toList());
}
Solução Java 8 (como essa, mas um pouco mais simples):
public static List<String> partition(String string, int partSize) {
List<String> parts = IntStream.range(0, string.length() / partSize)
.mapToObj(i -> string.substring(i * partSize, (i + 1) * partSize))
.collect(toList());
if ((string.length() % partSize) != 0)
parts.add(string.substring(string.length() / partSize * partSize));
return parts;
}
Perguntei a Alan Moore em um comentário para a solução aceita como lidar com seqüências de caracteres com novas linhas. Ele sugeriu o uso de DOTALL.
Usando sua sugestão, criei uma pequena amostra de como isso funciona:
public void regexDotAllExample() throws UnsupportedEncodingException {
final String input = "The\nquick\nbrown\r\nfox\rjumps";
final String regex = "(?<=\\G.{4})";
Pattern splitByLengthPattern;
String[] split;
splitByLengthPattern = Pattern.compile(regex);
split = splitByLengthPattern.split(input);
System.out.println("---- Without DOTALL ----");
for (int i = 0; i < split.length; i++) {
byte[] s = split[i].getBytes("utf-8");
System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s);
}
/* Output is a single entry longer than the desired split size:
---- Without DOTALL ----
[Idx: 0, length: 26] - [B@17cdc4a5
*/
//DOTALL suggested in Alan Moores comment on SO: https://stackoverflow.com/a/3761521/1237974
splitByLengthPattern = Pattern.compile(regex, Pattern.DOTALL);
split = splitByLengthPattern.split(input);
System.out.println("---- With DOTALL ----");
for (int i = 0; i < split.length; i++) {
byte[] s = split[i].getBytes("utf-8");
System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s);
}
/* Output is as desired 7 entries with each entry having a max length of 4:
---- With DOTALL ----
[Idx: 0, length: 4] - [B@77b22abc
[Idx: 1, length: 4] - [B@5213da08
[Idx: 2, length: 4] - [B@154f6d51
[Idx: 3, length: 4] - [B@1191ebc5
[Idx: 4, length: 4] - [B@30ddb86
[Idx: 5, length: 4] - [B@2c73bfb
[Idx: 6, length: 2] - [B@6632dd29
*/
}
Mas também gosto da solução @Jon Skeets em https://stackoverflow.com/a/3760193/1237974 . Para manutenção em projetos maiores, onde nem todos são igualmente experientes em expressões regulares, eu provavelmente usaria a solução Jons.
Outra solução de força bruta poderia ser,
String input = "thequickbrownfoxjumps";
int n = input.length()/4;
String[] num = new String[n];
for(int i = 0, x=0, y=4; i<n; i++){
num[i] = input.substring(x,y);
x += 4;
y += 4;
System.out.println(num[i]);
}
Onde o código apenas percorre a string com substrings
import static java.lang.System.exit;
import java.util.Scanner;
import Java.util.Arrays.*;
public class string123 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("Enter String");
String r=sc.nextLine();
String[] s=new String[10];
int len=r.length();
System.out.println("Enter length Of Sub-string");
int l=sc.nextInt();
int last;
int f=0;
for(int i=0;;i++){
last=(f+l);
if((last)>=len) last=len;
s[i]=r.substring(f,last);
// System.out.println(s[i]);
if (last==len)break;
f=(f+l);
}
System.out.print(Arrays.tostring(s));
}}
Resultado
Enter String
Thequickbrownfoxjumps
Enter length Of Sub-string
4
["Theq","uick","brow","nfox","jump","s"]
@Test
public void regexSplit() {
String source = "Thequickbrownfoxjumps";
// define matcher, any char, min length 1, max length 4
Matcher matcher = Pattern.compile(".{1,4}").matcher(source);
List<String> result = new ArrayList<>();
while (matcher.find()) {
result.add(source.substring(matcher.start(), matcher.end()));
}
String[] expected = {"Theq", "uick", "brow", "nfox", "jump", "s"};
assertArrayEquals(result.toArray(), expected);
}
Aqui está minha versão baseada nos fluxos RegEx e Java 8. Vale ressaltar que o Matcher.results()
método está disponível desde o Java 9.
Teste incluído.
public static List<String> splitString(String input, int splitSize) {
Matcher matcher = Pattern.compile("(?:(.{" + splitSize + "}))+?").matcher(input);
return matcher.results().map(MatchResult::group).collect(Collectors.toList());
}
@Test
public void shouldSplitStringToEqualLengthParts() {
String anyValidString = "Split me equally!";
String[] expectedTokens2 = {"Sp", "li", "t ", "me", " e", "qu", "al", "ly"};
String[] expectedTokens3 = {"Spl", "it ", "me ", "equ", "all"};
Assert.assertArrayEquals(expectedTokens2, splitString(anyValidString, 2).toArray());
Assert.assertArrayEquals(expectedTokens3, splitString(anyValidString, 3).toArray());
}
public static String[] split(String input, int length) throws IllegalArgumentException {
if(length == 0 || input == null)
return new String[0];
int lengthD = length * 2;
int size = input.length();
if(size == 0)
return new String[0];
int rep = (int) Math.ceil(size * 1d / length);
ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_16LE));
String[] out = new String[rep];
byte[] buf = new byte[lengthD];
int d = 0;
for (int i = 0; i < rep; i++) {
try {
d = stream.read(buf);
} catch (IOException e) {
e.printStackTrace();
}
if(d != lengthD)
{
out[i] = new String(buf,0,d, StandardCharsets.UTF_16LE);
continue;
}
out[i] = new String(buf, StandardCharsets.UTF_16LE);
}
return out;
}
public static List<String> getSplittedString(String stringtoSplit,
int length) {
List<String> returnStringList = new ArrayList<String>(
(stringtoSplit.length() + length - 1) / length);
for (int start = 0; start < stringtoSplit.length(); start += length) {
returnStringList.add(stringtoSplit.substring(start,
Math.min(stringtoSplit.length(), start + length)));
}
return returnStringList;
}