División de cadenas a subcadenas de igual longitud en Java

Cómo dividir la cadena "Thequickbrownfoxjumps" en subcadenas de igual tamaño en Java. P.ej. "Thequickbrownfoxjumps" de 4 tamaños iguales debería dar la salida.

 ["Theq","uick","brow","nfox","jump","s"] 

Pregunta similar:

División de cadena en subcadenas de igual longitud en Scala

Aquí está la versión regex one-liner:

 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, lo mismo que \A El aspecto subyacente coincide con la posición de cuatro caracteres a lo largo del final del último partido.

Tanto lookbehind como \G son funciones avanzadas de expresiones regulares, no compatibles con todos los sabores. Además, \G no se implementa de forma consistente en los sabores que sí 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 se podría utilizar de esta manera, incluso si JS admitió lookbehind.

Debo mencionar que no recomiendo necesariamente esta solución si tiene otras opciones. Las soluciones no-regex en las otras respuestas pueden ser más largas, pero también son auto-documentadas; este es todo lo contrario de eso. 😉

Además, esto no funciona en Android, que no admite el uso de \G en lookbehinds.

Bueno, es bastante fácil hacer esto por la fuerza bruta:

 public static List splitEqually(String text, int size) { // Give the list the right capacity to start with. You could use an array // instead if you wanted. List ret = new ArrayList((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 valga la pena usar una expresión regular para esto.

EDITAR: Mi razonamiento para no usar una expresión regular:

  • Esto no usa ninguna coincidencia de patrón real de expresiones regulares. Solo está contando.
  • Sospecho que lo anterior será más eficiente, aunque en la mayoría de los casos no importará
  • Si necesita usar tamaños de variable en diferentes lugares, tiene repetición o una función de ayuda para construir la expresión regular en función de un parámetro: ick.
  • La expresión regular proporcionada en otra respuesta, en primer lugar, no comstack (escapado no válido), y luego no funcionó. Mi código funcionó por primera vez. Eso es más un testimonio de la usabilidad de expresiones regulares vs código simple, IMO.

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:

  • Splitter.fixedLength()
  • Splitter.split()
  • Iterables.toArray()

Nota: La construcción del divisor se muestra en línea arriba, pero como 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); } 

Si está utilizando las bibliotecas de propósito general de guayaba de Google (y honestamente, cualquier nuevo proyecto de 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 todo . ¡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 
 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; } 

Puede usar una substring de String.class (manejo de excepciones) o de Apache lang commons (maneja excepciones para usted)

 static String substring(String str, int start, int end) 

Ponlo dentro de un bucle y estarás listo para ir.

Prefiero esta simple solución:

 String content = "Thequickbrownfoxjumps"; while(content.length() > 4) { System.out.println(content.substring(0, 4)); content = content.substring(4); } System.out.println(content); 

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; } 

Aquí hay una implementación de un trazador de líneas utilizando las transmisiones Java8:

 String input = "Thequickbrownfoxjumps"; final AtomicInteger atomicInteger = new AtomicInteger(0); Collection 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] 

Le pregunté a @Alan Moore en un comentario sobre la solución aceptada cómo se podrían manejar las cadenas con nuevas líneas. Él sugirió usar DOTALL.

Usando su sugerencia, creé una pequeña muestra de cómo funciona eso:

 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 de @Jon Skeets en https://stackoverflow.com/a/3760193/1237974 . Para la mantenibilidad en proyectos más grandes donde no todos tienen la misma experiencia en expresiones regulares, probablemente usaría la solución de 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 

Donde el código simplemente pasa por 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 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 las streams RegEx y Java 8. Vale la pena mencionar que el método Matcher.results() está disponible desde Java 9.

Prueba incluida

 public static List 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()); }