Cómo dividir la cadena "Thequickbrownfoxjumps"
en subcadenas de igual tamaño en Java. P.ej. "Thequickbrownfoxjumps"
de 4 de igual tamaño debería dar la salida.
["Theq","uick","brow","nfox","jump","s"]
Pregunta similar:
Cómo dividir la cadena "Thequickbrownfoxjumps"
en subcadenas de igual tamaño en Java. P.ej. "Thequickbrownfoxjumps"
de 4 de igual tamaño debería dar la salida.
["Theq","uick","brow","nfox","jump","s"]
Pregunta similar:
Respuestas:
Aquí está la versión de una sola línea regex:
System.out.println(Arrays.toString(
"Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
\G
es una aserción de ancho cero que coincide con la posición donde terminó la coincidencia anterior. Si no hubo una coincidencia previa, coincide con el comienzo de la entrada, igual que \A
. La mirada de retrospectiva adjunta coincide con la posición de cuatro caracteres desde el final de la última coincidencia.
Ambos miran hacia atrás y \G
son características avanzadas de expresiones regulares, no compatibles con todos los sabores. Además, \G
no se implementa de manera consistente en todos los sabores que lo admiten. Este truco funcionará (por ejemplo) en Java , Perl, .NET y JGSoft, pero no en PHP (PCRE), Ruby 1.9+ o TextMate (ambos Oniguruma). JavaScript /y
(bandera adhesiva) no es tan flexible como \G
, y no podría usarse de esta manera, incluso si JS admitiera mirar hacia atrás.
Debo mencionar que no necesariamente recomiendo esta solución si tiene otras opciones. Las soluciones que no son expresiones regulares en las otras respuestas pueden ser más largas, pero también se documentan por sí mismas; este es casi lo contrario de eso. ;)
Además, esto no funciona en Android, que no admite el uso de \G
lookbehinds.
String.substring()
lugar de una expresión regular, mientras se requieren algunas líneas de código adicionales, se ejecutará en algún lugar del orden de 5 veces más rápido ...
(?s)
en la expresión regular: (?s)(?<=\\G.{4})
.
java.util.regex.PatternSyntaxException: Look-behind pattern matches must have a bounded maximum length
Bueno, es bastante fácil hacer esto con operaciones aritméticas y de cadena 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;
}
No creo que realmente valga la pena usar una expresión regular para esto.
EDITAR: Mi razonamiento para no usar una expresión regular:
Splitter.fixedLength(4)
como lo sugiere Seanizer.
Esto es muy fácil con Google Guava :
for(final String token :
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
Salida:
Theq
uick
brow
nfox
jump
s
O si necesita el resultado como una matriz, puede usar este código:
String[] tokens =
Iterables.toArray(
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps"),
String.class
);
Referencia:
Nota: la construcción del divisor se muestra en línea arriba, pero dado que los divisores son inmutables y reutilizables, es una buena práctica almacenarlos en 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)
Si está utilizando las bibliotecas de propósito general de guayaba de Google (y, sinceramente, cualquier nuevo proyecto Java probablemente debería serlo), esto es increíblemente trivial con la clase Splitter :
for (String substring : Splitter.fixedLength(4).split(inputString)) {
doSomethingWith(substring);
}
y eso es lo . Tan 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()
y s, su llamada no está logrando lo que desea, vea cómo algunas de las otras respuestas lo están haciendo: (src.length () + len - 1) / lenlen
int
ceiling
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
bucles?
for
bucle es, de hecho, una opción de uso más 'natural' para esto :-) Gracias por señalar esto.
Puede usar substring
desde String.class
(manejo de excepciones) o desde Apache lang commons (maneja excepciones por usted)
static String substring(String str, int start, int end)
Ponlo dentro de un bucle y listo.
substring
método en la String
clase estándar ?
Prefiero esta solución simple:
String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
System.out.println(content.substring(0, 4));
content = content.substring(4);
}
System.out.println(content);
substring
implementación cambió con Java 7, actualización 6 a mediados de 2012, cuando los campos offset
y count
se eliminaron de la String
clase. Por lo tanto, la complejidad se substring
volvió lineal mucho antes de que se hiciera esta respuesta. Pero para una cadena pequeña como el ejemplo, todavía se ejecuta lo suficientemente rápido y para cadenas más largas ... bueno, esta tarea rara vez ocurre en la práctica.
Aquí hay una implementación de una línea utilizando flujos 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();
Da el siguiente resultado:
[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);
Aquí hay una versión de una línea que utiliza Java 8 IntStream para determinar los índices de los inicios de la porción:
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);
En caso de que quiera dividir la cadena igualmente hacia atrás, es decir, de derecha a izquierda, por ejemplo, para dividir 1010001111
a [10, 1000, 1111]
, aquí está el 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;
}
Yo uso la siguiente solución de 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());
}
Solución Java 8 (como esta pero un poco más simple):
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;
}
Le pregunté a @Alan Moore en un comentario a la solución aceptada cómo se podían manejar las cadenas con líneas nuevas. Sugirió usar DOTALL.
Usando su sugerencia, creé una pequeña muestra de cómo 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
*/
}
Pero también me gusta la solución @Jon Skeets en https://stackoverflow.com/a/3760193/1237974 . Para el mantenimiento en proyectos más grandes donde no todos tienen la misma experiencia en expresiones regulares, probablemente usaría la solución Jons.
Otra solución de fuerza bruta podría 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]);
}
Donde el código solo atraviesa la cadena con subcadenas
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);
}
Aquí está mi versión basada en transmisiones RegEx y Java 8. Vale la pena mencionar que el Matcher.results()
método está disponible desde Java 9.
Prueba incluida.
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;
}