2009-07-08 27 views
107

Dada una cadena que no es demasiado larga, ¿cuál es la mejor manera de leerla línea por línea?Leer cadena línea por línea

Sé que usted puede hacer:

BufferedReader reader = new BufferedReader(new StringReader(<string>)); 
reader.readLine(); 

Otra forma sería tomar la subcadena en la EOL:

final String eol = System.getProperty("line.separator"); 
output = output.substring(output.indexOf(eol + 1)); 

alguna otra manera tal vez más sencillas de hacerlo? No tengo problemas con los enfoques anteriores, solo me interesa saber si alguno de ustedes sabe algo que puede parecer más simple y más eficiente.

+4

bien su requerimiento dicho "leer línea por línea", lo que implica que no es necesario que todas las líneas en la memoria a la vez, así que me gustaría seguir con el enfoque BufferedReader o Scanner, con el que se sienta más cómodo (no sé cuál es más eficiente). De esta forma, tus requisitos de memoria son menores. También le permitirá "escalar" la aplicación para usar cadenas más grandes al leer datos de un archivo en el futuro. – camickr

Respuesta

96

También puede utilizar el método split de encordado:

String[] lines = myString.split(System.getProperty("line.separator")); 

Esto le da todas las líneas en una matriz práctico.

No sé sobre el rendimiento de split. Utiliza expresiones regulares.

+2

Y espero que el separador de línea no tenga caracteres de expresiones regulares. :) –

+36

"line.separator" no es confiable de todos modos. El hecho de que el código se esté ejecutando (por ejemplo) en Unix, ¿qué impide que el archivo tenga separadores de línea "\ r \ n" al estilo de Windows? BufferedReader.readLine() y Scanner.nextLine() siempre comprueban los tres estilos de separador. –

+4

Sé que este comentario es muy antiguo, pero ... La pregunta no menciona los archivos en absoluto. Suponiendo que la cadena no se leyó desde un archivo, este enfoque es probablemente seguro. – Jolta

161

También hay Scanner. Se puede utilizar al igual que el BufferedReader:

Scanner scanner = new Scanner(myString); 
while (scanner.hasNextLine()) { 
    String line = scanner.nextLine(); 
    // process the line 
} 
scanner.close(); 

creo que este es un enfoque poco más limpia que ambos los sugeridos.

+5

No creo que sea una comparación justa, String.split depende de que toda la entrada se lea en la memoria, lo que no siempre es factible (por ejemplo, para archivos grandes). – Adamski

+3

La entrada debe residir en la memoria, dado que la entrada es String. La sobrecarga de memoria es la matriz. Además, las cadenas resultantes reutilizan la misma matriz de caracteres back-end. – notnoop

+10

No olvide cerrar el escáner después de terminar de leer. –

20

Usando Apache Commons IOUtils Esto se puede hacer muy bien a través de

List<String> lines = IOUtils.readLines(new StringReader(string)); 

No está haciendo nada inteligente, pero es agradable y compacto. Manejará las transmisiones también, y también puede obtener un LineIterator si lo prefiere.

+2

Una desventaja de este enfoque es que 'IOUtils.readlines (Reader)' arroja una 'IOException'. Aunque esto probablemente nunca ocurra con un StringReader, tendrás que atraparlo o declararlo. – sleske

+0

Hay un ligero error tipográfico, debería ser: List lines = IOUtils.readLines (new StringReader (string)); –

5

También puede utilizar:

String[] lines = someString.split("\n"); 

Si eso no funciona, intente reemplazar \n con \r\n.

+1

La codificación rígida de la representación de nueva línea hace que la solución dependa de la plataforma. – thSoft

28

Como estaba especialmente interesado en el ángulo de eficiencia, creé una pequeña clase de prueba (abajo). Resultado de 5.000.000 líneas:

Comparing line breaking performance of different solutions 
Testing 5000000 lines 
Split (all): 14665 ms 
Split (CR only): 3752 ms 
Scanner: 10005 
Reader: 2060 

Como de costumbre, los tiempos exactos pueden variar, pero la relación es válido sin embargo a menudo me he encontrado él.

Conclusión: los requisitos "más simples" y "más eficientes" de OP no se pueden cumplir simultáneamente, la solución split (en cualquiera de las encarnaciones) es más simple, pero la implementación Reader supera a los demás.

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.StringReader; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Scanner; 

/** 
* Test class for splitting a string into lines at linebreaks 
*/ 
public class LineBreakTest { 
    /** Main method: pass in desired line count as first parameter (default = 10000). */ 
    public static void main(String[] args) { 
     int lineCount = args.length == 0 ? 10000 : Integer.parseInt(args[0]); 
     System.out.println("Comparing line breaking performance of different solutions"); 
     System.out.printf("Testing %d lines%n", lineCount); 
     String text = createText(lineCount); 
     testSplitAllPlatforms(text); 
     testSplitWindowsOnly(text); 
     testScanner(text); 
     testReader(text); 
    } 

    private static void testSplitAllPlatforms(String text) { 
     long start = System.currentTimeMillis(); 
     text.split("\n\r|\r"); 
     System.out.printf("Split (regexp): %d%n", System.currentTimeMillis() - start); 
    } 

    private static void testSplitWindowsOnly(String text) { 
     long start = System.currentTimeMillis(); 
     text.split("\n"); 
     System.out.printf("Split (CR only): %d%n", System.currentTimeMillis() - start); 
    } 

    private static void testScanner(String text) { 
     long start = System.currentTimeMillis(); 
     List<String> result = new ArrayList<>(); 
     try (Scanner scanner = new Scanner(text)) { 
      while (scanner.hasNextLine()) { 
       result.add(scanner.nextLine()); 
      } 
     } 
     System.out.printf("Scanner: %d%n", System.currentTimeMillis() - start); 
    } 

    private static void testReader(String text) { 
     long start = System.currentTimeMillis(); 
     List<String> result = new ArrayList<>(); 
     try (BufferedReader reader = new BufferedReader(new StringReader(text))) { 
      String line = reader.readLine(); 
      while (line != null) { 
       result.add(line); 
       line = reader.readLine(); 
      } 
     } catch (IOException exc) { 
      // quit 
     } 
     System.out.printf("Reader: %d%n", System.currentTimeMillis() - start); 
    } 

    private static String createText(int lineCount) { 
     StringBuilder result = new StringBuilder(); 
     StringBuilder lineBuilder = new StringBuilder(); 
     for (int i = 0; i < 20; i++) { 
      lineBuilder.append("word "); 
     } 
     String line = lineBuilder.toString(); 
     for (int i = 0; i < lineCount; i++) { 
      result.append(line); 
      result.append("\n"); 
     } 
     return result.toString(); 
    } 
} 
+3

A partir de Java8, el BufferedReader tiene una función 'lines()' que devuelve un 'Stream ' de las líneas, que puede recopilar en una lista si lo desea, o procesar la transmisión. –

1

Con Guayaba:

ImmutableList<String> lines = CharSource.wrap(str).readLines(); 
2

O utilizar las nuevas tratar con cláusula de recursos combinada con escáner:

try (Scanner scanner = new Scanner(value)) { 
     while (scanner.hasNextLine()) { 
      String line = scanner.nextLine(); 
      // process the line 
     } 
    } 
3

Usted puede utilizar la API arroyo y un StringReader envuelto en un BufferedReader que consiguió a lines() secuencia de salida en java 8:

import java.util.stream.*; 
import java.io.*; 
class test { 
    public static void main(String... a) { 
     String s = "this is a \nmultiline\rstring\r\nusing different newline styles"; 

     new BufferedReader(new StringReader(s)).lines().forEach(
      (line) -> System.out.println("one line of the string: " + line) 
     ); 
    } 
} 

Da

one line of the string: this is a 
one line of the string: multiline 
one line of the string: string 
one line of the string: using different newline styles 

Al igual que en readLine de BufferedReader, no están incluidos el carácter de nueva línea (s) de ellos mismos. Se admiten todo tipo de separadores de línea nueva (en la misma cadena, incluso).

+0

¡Ni siquiera lo sabía! Muchas gracias . – GOXR3PLUS

8

solución utilizando Java 8 características tales como Stream API y Method references

new BufferedReader(new StringReader(myString)) 
     .lines().forEach(System.out::println); 

o

public void someMethod(String myLongString) { 

    new BufferedReader(new StringReader(myLongString)) 
      .lines().forEach(this::parseString); 
} 

private void parseString(String data) { 
    //do something 
} 
0

Usted puede probar la siguiente expresión regular:

\r?\n 

Código:

String input = "\nab\n\n \n\ncd\nef\n\n\n\n\n"; 
String[] lines = input.split("\\r?\\n", -1); 
int n = 1; 
for(String line : lines) { 
    System.out.printf("\tLine %02d \"%s\"%n", n++, line); 
} 

Salida:

Line 01 "" 
Line 02 "ab" 
Line 03 "" 
Line 04 " " 
Line 05 "" 
Line 06 "cd" 
Line 07 "ef" 
Line 08 "" 
Line 09 "" 
Line 10 "" 
Line 11 "" 
Line 12 "" 
Cuestiones relacionadas