2012-02-13 14 views
37

Attualmente sto usando qualcosa come:Qual è il modo migliore per scorrere le righe di una stringa Java?

String[]lines = textContent.split(System.getProperty("line.separator")); 
for(String tmpLine : lines){ 
    //do something 
} 

io non sono molto contento di questo metodo perché creare un array pesanti (per non dire textContent può contenere un libro).

C'è qualche soluzione migliore per scorrere sulle linee di un String?

risposta

41

si potrebbe usare:

BufferedReader bufReader = new BufferedReader(new StringReader(textContent)); 

e utilizzare il metodo readLine():

String line=null; 
while((line=bufReader.readLine()) != null) 
{ 

} 
+0

Grazie per la risposta. Questa soluzione offre prestazioni migliori? Ho notato che questa soluzione utilizza ** 3 ** oggetto. Voglio limitare la creazione di oggetti per avere memoria sufficiente, quindi 'BufferedReader' e' StringReader' sono più leggeri di un array String? –

+0

Come javadoc per gli stati di BufferedReader, l'utilizzo di tale classe è un mezzo valido per il confezionamento di metodi di lettura costosi per letture economicamente convenienti. Vedi http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html –

6

Si potrebbe utilizzare String.indexOf()/String.substring()

String separator = System.getProperty("line.separator"); 
int index = textContent.indexOf(separator); 

while (index > 0) 
{ 
    int nextIndex = textContent.indexOf(separator, index + separator.length()); 
    String line = textContent.substring(index + separator.length(), nextIndex); 

    // do something with line. 
} 
3

Che mi dici della classe java.util.Scanner?

In sintesi:

Un semplice scanner di testo che può analizzare i tipi e le stringhe primitivi utilizzando le espressioni regolari.

Uno scanner interrompe il proprio input in token utilizzando un pattern delimitatore, che corrisponde per default allo spazio bianco. I token risultanti possono quindi essere convertiti in valori di tipi diversi utilizzando i vari metodi successivi .

e di nota per lo scenario:

Lo scanner può anche utilizzare delimitatori diversi spazi. Questo esempio legge diversi elementi in da una stringa:

 String input = "1 fish 2 fish red fish blue fish"; 
    Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*"); 
    System.out.println(s.nextInt()); 
    System.out.println(s.nextInt()); 
    System.out.println(s.next()); 
    System.out.println(s.next()); 
    s.close(); 
1

uso BufferedReader con l'argomento StringReader. BufferedReader ha un metodo readLine() in modo da poter leggere la stringa riga per riga.

StringReader reader = new StringReader(myBigTextString); 
    BufferedReader br = new BufferedReader(reader); 
    String line; 
    while((line=br.readLine())!=null) 
    { 
     //do what you want 
    } 
+1

@ alain.janinm, quando si mantiene un array di linee divise che l'array occupa molta memoria come hai detto . In questo caso tutte le righe del testo non vengono caricate in memoria. BufferedReader si limita a ricordare l'ultimo punto di lettura e quando si chiama il metodo readLine() legge semplicemente la riga successiva della stringa (con l'aiuto di StringReader). Quindi in ogni iterazione hai una sola riga del tuo testo in memoria (nella variabile 'line') invece di tutte le righe. – shift66

1

Unire java.io.StringReader e java.io.LineNumberReader

+0

Grazie per la risposta. altro proposto 'BufferedReader'. Quali sono i vantaggi di 'java.io.LineNumberReader'? –

+0

In realtà, non mi sono reso conto che BufferedReader ha implementato anche il metodo readLine(). –

+0

Per i futuri lettori: LineNumberReader estende BufferedReader, quindi LineNumberReader è una sostituzione drop-in per BufferedReader con il comportamento aggiunto di tracciare il numero di riga della linea appena letta. Vedi http://docs.oracle.com/javase/8/docs/api/java/io/LineNumberReader.html. – MonkeyWithDarts

5

Splitter opere di Guava bene. Tanto più che è possibile rimuovere le righe vuote

Splitter splitter = Splitter.on(System.getProperty("line.separator")) 
          .trimResults() 
          .omitEmptyStrings(); 
for (String line : splitter.split(input)){ 
    // do work here 
} 
+2

Dal codice sorgente di guava: '' 'Splitter.on (Pattern.compile (" \ r? \ N ")). Split (interoFile)' '' –

+0

Più precisamente, è in Javadoc per 'Splitter # on': https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Splitter.html#on-java.util.regex.Pattern- – simon04

12

Per aggiungere il modo Java 8 a questa domanda:

Arrays.stream(content.split("\\r?\\n")).forEach(line -> /*do something */) 

Di maledizione è anche possibile utilizzare System.lineSeparator() di dividere se si è certi che il file sta venendo da la stessa piattaforma in cui gira il vm.

O meglio ancora utilizzare il flusso di api ancora più agressiv con filtro, mappa e raccogliere:

String result = Arrays.stream(content.split(System.lineSeparator())) 
        .filter(/* filter for lines you are interested in*/) 
        .map(/*convert string*/) 
        .collect(Collectors.joining(";")); 
+0

probabilmente utilizzare il vero modo java8 'System.lineSeparator()' invece della proprietà direttamente – xenoterracide

+0

@xenoterracide hai ragione! Modificata la risposta di conseguenza. – leo

+0

Hai accidentalmente modificato la parte 'content' nel tuo secondo esempio. – Torque

1

Si può effettivamente disputare Scanner per consentire di utilizzare un normale for ciclo:

import java.util.Scanner; 
public class IterateLines { 
    public static void main(String[] args) { 
     Iterable<String> sc =() -> 
      new Scanner("foo bar\nbaz\n").useDelimiter("\n"); 
     for (String line: sc) { 
      System.out.println(line); 
     } 
    } 
} 

ci dà:

$ javac IterateLines.java && java IterateLines 
foo bar 
baz 
+0

Questo dividerà la stringa su entrambi gli spazi e le nuove linee, che non è ciò che la domanda sta cercando. – Zulakis

+0

Grazie a @Zulakis: ho corretto il codice per utilizzare un delimitatore esplicito. –

Problemi correlati