2012-02-13 35 views
37

Hiện nay tôi đang sử dụng một cái gì đó như:Cách tốt nhất để lặp qua các dòng của một chuỗi Java là gì?

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

Tôi không phải là rất vui mừng của phương pháp này vì nó tạo ra một mảng lớn (hãy nói textContent có thể chứa một cuốn sách).

Có giải pháp nào tốt hơn để lặp qua các dòng của String không?

Trả lời

41

Bạn có thể sử dụng:

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

Và sử dụng các phương pháp readLine():

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

} 
+0

Cảm ơn câu trả lời. Giải pháp này có mang lại hiệu suất tốt hơn không? Tôi nhận thấy rằng giải pháp này sử dụng đối tượng ** 3 **. Tôi muốn giới hạn việc tạo đối tượng để có đủ bộ nhớ, do đó, 'BufferedReader' và' StringReader' là nhẹ hơn một mảng String? –

+0

Như javadoc cho các trạng thái BufferedReader, sử dụng lớp đã nói là một phương tiện hợp lệ để gói các phương thức đọc tốn kém để đọc chi phí hiệu quả. Xem http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html –

6

Bạn có thể sử dụng 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

Còn lớp học java.util.Scanner thì sao?

Nói tóm lại:

Một máy quét văn bản đơn giản mà có thể phân tích các kiểu dữ liệu và chuỗi sử dụng biểu thức thông thường.

Máy quét ngắt đầu vào của nó thành mã thông báo bằng cách sử dụng mẫu phân cách, theo mặc định khớp với khoảng trắng. Các mã thông báo kết quả sau đó có thể là được chuyển đổi thành các giá trị của các loại khác nhau bằng cách sử dụng các phương thức tiếp theo khác nhau.

và chú ý cho kịch bản của bạn:

Máy quét cũng có thể sử dụng delimiters khác hơn là khoảng trắng. ví dụ này đọc nhiều mục cùng lúc từ một chuỗi:

 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

sử dụng BufferedReader với lập luận StringReader. BufferedReader có một phương thức readLine() để bạn có thể đọc chuỗi ký tự của bạn theo dòng.

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

@ alain.janinm, khi bạn giữ một mảng các dòng được chia nhỏ mà mảng chiếm rất nhiều bộ nhớ như bạn đã nói . Trong trường hợp này, tất cả các dòng văn bản của bạn không được tải trong bộ nhớ. BufferedReader chỉ nhớ lại điểm đọc cuối cùng và khi bạn gọi phương thức readLine() nó chỉ đọc dòng tiếp theo của chuỗi của bạn (với sự trợ giúp của StringReader). Vì vậy, trong mỗi lần lặp, bạn chỉ có một dòng văn bản trong bộ nhớ (trong biến 'dòng') thay vì tất cả các dòng. – shift66

1

Kết hợp java.io.StringReaderjava.io.LineNumberReader

+0

Cảm ơn câu trả lời. đề xuất 'BufferedReader' khác. Ưu điểm của 'java.io.LineNumberReader' là gì? –

+0

Trên thực tế, tôi chỉ không nhận ra BufferedReader có readLine() phương pháp thực hiện là tốt. –

+0

Đối với người đọc trong tương lai: LineNumberReader mở rộng BufferedReader, do đó, LineNumberReader là một thay thế drop-in cho BufferedReader với hành vi thêm vào theo dõi số dòng của dòng bạn vừa đọc. Xem http://docs.oracle.com/javase/8/docs/api/java/io/LineNumberReader.html. – MonkeyWithDarts

5

Splitter công trình Ổi giếng. Điều đặc biệt là bạn có thể xóa các dòng trống

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

Từ mã nguồn của ổi: '' 'Splitter.on (Pattern.compile (" \ r? \ N ")). Split (wholeFile)' '' –

+0

Chính xác hơn, nó nằm trong Javadoc cho 'Splitter # on': https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Splitter.html#on-java.util.regex.Pattern- – simon04

12

Để thêm cách Java 8 cho câu hỏi này:

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

Trong lời nguyền bạn cũng có thể sử dụng System.lineSeparator() để chia ra nếu bạn chắc chắn rằng các tập tin được đến từ cùng một plattform như vm chạy trên.

Hoặc thậm chí tốt hơn sử dụng các dòng api agressiv thậm chí nhiều hơn với bộ lọc, lập bản đồ và thu thập:

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

cách java8 thực có thể sẽ sử dụng 'System.lineSeparator()' thay cho thuộc tính trực tiếp – xenoterracide

+0

@xenoterracide bạn nói đúng! Thay đổi câu trả lời cho phù hợp. – leo

+0

Bạn vô tình chỉnh sửa phần 'nội dung' trong ví dụ thứ hai của mình. – Torque

1

Bạn thực sự có thể wrangle Scanner để cho phép bạn sử dụng một bình thường for loop:

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

cung cấp cho chúng tôi:

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

Điều này sẽ chia chuỗi trên cả dấu cách và dòng mới, không phải là câu hỏi đang tìm kiếm. – Zulakis

+0

Cảm ơn @Zulakis - Tôi đã sửa mã để sử dụng dấu phân tách rõ ràng. –

Các vấn đề liên quan