2013-04-01 42 views
40

Tôi có tệp được phân cách bằng dấu phẩy có nhiều dòng tương tự như dưới đây.Tách tệp csv bằng dấu ngoặc kép làm dấu phân tách văn bản bằng cách sử dụng String.split()

Sachin,,M,"Maths,Science,English",Need to improve in these subjects. 

Báo giá được sử dụng để thoát dấu phẩy phân cách được sử dụng để biểu thị nhiều giá trị.

Bây giờ, làm cách nào để chia giá trị trên trên dấu phân cách bằng dấu phẩy bằng cách sử dụng String.split() nếu có thể?

+2

Tại sao bạn cứ khăng khăng về việc sử dụng String.split? Có những lựa chọn tốt hơn cho ví dụ này? – user949300

Trả lời

134
public static void main(String[] args) { 
    String s = "Sachin,,M,\"Maths,Science,English\",Need to improve in these subjects."; 
    String[] splitted = s.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"); 
    System.out.println(Arrays.toString(splitted)); 
} 

Output:

[Sachin, , M, "Maths,Science,English", Need to improve in these subjects.] 
+13

+1 đây là rất regex mát mẻ. Tôi chưa từng thấy điều này trước đây, nhưng nó hoạt động! Tôi cảm thấy điều này rất tốt Tôi sẽ trao cho bạn một khoản tiền thưởng :) (Lưu ý: quá trình tiền thưởng mất nhiều ngày để hoàn thành) – Bohemian

+5

Tôi mất một thời gian để tìm hiểu xem regex này đang làm gì. Nó đã giúp tôi rất nhiều để có lời giải thích rằng nó phù hợp với dấu phẩy được theo sau bởi một số thậm chí trích dẫn (hoặc không có dấu ngoặc kép). Vì vậy, điều này làm việc bởi vì dấu ngoặc kép bên trong của dấu phẩy (tức là những cái chúng tôi không muốn khớp/chia nhỏ) nên có một số dấu ngoặc kép lẻ giữa chúng và cuối dòng. Nó cũng có thể đáng chú ý là tôi tin rằng điều này sẽ không hoạt động nếu dữ liệu có thể đã thoát khỏi dấu ngoặc kép trong đó. – glyphx

+1

Thực hiện điều này s.split (', (? = ([^ \ "] * \" [^ \ "] * \") * [^ \ "] * $)', -1) nếu bạn muốn giữ trống các chuỗi ở cuối. http://stackoverflow.com/questions/13939675/java-string-split-i-want-it-to-include-the-empty-strings-at-the-end – kctang

6

Nếu chuỗi của bạn đều tốt được hình thành có thể với các biểu thức chính quy sau:

String[] res = str.split(",(?=([^\"]|\"[^\"]*\")*$)"); 

Khái niệm đảm bảo rằng sự chia rẽ chỉ xảy ra ở dấu phẩy mà được theo sau bởi một số chẵn (hoặc không có) của báo giá (và do đó không phải bên trong dấu ngoặc kép như vậy).

Tuy nhiên, có thể dễ dàng sử dụng trình phân tích cú pháp không phải regex đơn giản.

+0

để đọc tệp csv nó hoạt động tốt. Nếu bạn có loại định dạng này là 987663, seepzBranch, "Seepz mumbai, andheri", "gần infra, flat no 23, raghilla mall thane", seepz, –

9

Như vấn đề/yêu cầu của bạn không được tất cả những gì phức tạp một phương pháp tùy chỉnh có thể được sử dụng mà thực hiện hơn 20 lần nhanh hơn và tạo ra kết quả tương tự. Đây là biến số dựa trên kích thước dữ liệu và số hàng được phân tích cú pháp và đối với các vấn đề phức tạp hơn khi sử dụng cụm từ thông dụng là phải.

import java.util.Arrays; 
import java.util.ArrayList; 
public class SplitTest { 

public static void main(String[] args) { 

    String s = "Sachin,,M,\"Maths,Science,English\",Need to improve in these subjects."; 
    String[] splitted = null; 

//Measure Regular Expression 
    long startTime = System.nanoTime(); 
    for(int i=0; i<10; i++) 
    splitted = s.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"); 
    long endTime = System.nanoTime(); 

    System.out.println("Took: " + (endTime-startTime)); 
    System.out.println(Arrays.toString(splitted)); 
    System.out.println(""); 


    ArrayList<String> sw = null;   
//Measure Custom Method 
      startTime = System.nanoTime(); 
    for(int i=0; i<10; i++) 
    sw = customSplitSpecific(s); 
    endTime = System.nanoTime(); 

    System.out.println("Took: " + (endTime-startTime)); 
    System.out.println(sw);   
} 

public static ArrayList<String> customSplitSpecific(String s) 
{ 
    ArrayList<String> words = new ArrayList<String>(); 
    boolean notInsideComma = true; 
    int start =0, end=0; 
    for(int i=0; i<s.length()-1; i++) 
    { 
     if(s.charAt(i)==',' && notInsideComma) 
     { 
      words.add(s.substring(start,i)); 
      start = i+1;     
     } 
     else if(s.charAt(i)=='"') 
     notInsideComma=!notInsideComma; 
    } 
    words.add(s.substring(start)); 
    return words; 
} 

}

Trên máy tính của riêng tôi này sản xuất:

Took: 6651100 
[Sachin, , M, "Maths,Science,English", Need to improve in these subjects.] 

Took: 224179 
[Sachin, , M, "Maths,Science,English", Need to improve in these subjects.] 
+0

-1 Điều này không trả lời được câu hỏi, cụ thể yêu cầu một giải pháp sử dụng 'String.split()'. Là một sang một bên, một trong những điểm nổi bật của mã được viết bởi một người biết rất ít về java là việc sử dụng 'Vector'. – Bohemian

+4

Vui lòng giải thích tại sao trong tình huống này sẽ thuận lợi hơn khi sử dụng ArrayList thay vì Vector (ngoại trừ hiệu suất đạt được do độ an toàn của luồng). Ngoài ra, sự lịch sự của bạn có thể sử dụng một số công việc, đó là một trong những điểm nổi bật của một người thô lỗ. –

+0

Tôi không thô lỗ; chỉ đơn thuần là thực tế. Đây là một mẹo nhỏ ... 'Vector' là * không * threadsafe. Đó là một lớp học bị phá vỡ, đó là lý do tại sao không ai, và tôi thực sự có ý nghĩa * không ai *, sử dụng nó trong thế giới thực. Chỉ có những người mới bắt đầu sử dụng nó, tôi đoán là bởi vì các bài thuyết trình là mười năm lỗi thời, và đặc biệt là bởi vì các giảng viên ủng hộ việc sử dụng Vector đã dành quá nhiều thời gian trong học viện để giữ liên lạc và câu ngạn ngữ cũ "nếu bạn không thể làm nó, dạy nó "vẫn đúng. – Bohemian

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