2009-09-17 28 views
15

Tôi biết, bây giờ tôi có hai vấn đề. Nhưng tôi đang vui vẻ!Phân tích cú pháp đầu vào CSV bằng RegEx trong java

Tôi bắt đầu với this advice không để thử và chia tách, mà thay vào đó để khớp với trường được chấp nhận là gì và mở rộng từ đó sang biểu thức này.

final Pattern pattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?=,|$)"); 

Biểu thức trông như thế này mà không có sự khó chịu thoát dấu ngoặc kép:

"([^"]*)"|(?<=,|^)([^,]*)(?=,|$) 

này đang làm việc tốt cho tôi - hoặc nó phù hợp trên "hai dấu ngoặc kép và bất cứ điều gì là giữa chúng", hoặc "một cái gì đó giữa bắt đầu của dòng hoặc dấu phẩy và cuối dòng hoặc dấu phẩy ". Lặp đi lặp lại qua các trận đấu giúp tôi có được tất cả các lĩnh vực, ngay cả khi chúng trống rỗng. Ví dụ,

the quick, "brown, fox jumps", over, "the",,"lazy dog" 

chia ra làm

the quick 
"brown, fox jumps" 
over 
"the" 

"lazy dog" 

Tuyệt vời! Bây giờ tôi muốn thả các dấu ngoặc kép, vì vậy tôi đã thêm vào các lookahead và lookbehind nhóm không bắt giữ như tôi đã làm cho dấu phẩy.

final Pattern pattern = Pattern.compile("(?<=\")([^\"]*)(?=\")|(?<=,|^)([^,]*)(?=,|$)"); 

lại biểu thức là:

(?<=")([^"]*)(?=")|(?<=,|^)([^,]*)(?=,|$) 

Thay vì kết quả mong muốn

the quick 
brown, fox jumps 
over 
the 

lazy dog 

bây giờ tôi có được sự cố này:

the quick 
"brown 
fox jumps" 
,over, 
"the" 
,, 
"lazy dog" 

tôi thiếu gì?

+0

Tôi cho rằng văn bản của bạn không bao giờ có thể tự chứa dấu ngoặc kép? –

+2

Rất may là không. Tại thời điểm đó tôi sẽ chỉ sử dụng thư viện openCSV. –

+0

thư viện CSV khác cho Java: http://stackoverflow.com/questions/101100/csv-api-for-java – Thilo

Trả lời

8

Ưu tiên toán tử. Về cơ bản không có. Đó là tất cả trái sang phải. Vì vậy, hoặc (|) được áp dụng cho lookahead đóng cửa báo giá và các lookahead dấu phẩy

Hãy thử:

(?:(?<=")([^"]*)(?="))|(?<=,|^)([^,]*)(?=,|$) 
+0

Ah, tôi hiểu. Vì vậy, tôi nên cố gắng để nhóm các công cụ báo giá với nhau, và cũng là công cụ dấu phẩy. Thật không may kèm theo các công cụ trích dẫn trong (?:) Dường như không có bất kỳ ảnh hưởng nào. Tôi đã thử thêm nó vào các công cụ dấu phẩy quá, và cũng chỉ nhóm cả hai trong số họ trong một bộ ngoặc đơn, không ai trong số đó có bất kỳ tác dụng. Tôi sẽ tiếp tục tìm kiếm cú pháp chính xác; nếu tôi tìm thấy nó trước khi ai đó đăng nó, tôi sẽ trả lời bạn. –

4

Khi tôi bắt đầu hiểu những gì tôi đã làm sai, tôi cũng bắt đầu hiểu được cách thức phức tạp các lookarounds đã làm điều này. Cuối cùng tôi nhận ra rằng tôi không muốn tất cả các văn bản phù hợp, tôi muốn các nhóm cụ thể bên trong nó. Tôi đã kết thúc bằng cách sử dụng một cái gì đó rất giống với RegEx ban đầu của tôi ngoại trừ việc tôi đã không làm một lookahead trên dấu phẩy đóng cửa, mà tôi nghĩ rằng nên được một chút hiệu quả hơn. Đây là mã cuối cùng của tôi.

package regex.parser; 

import java.util.ArrayList; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class CSVParser { 

    /* 
    * This Pattern will match on either quoted text or text between commas, including 
    * whitespace, and accounting for beginning and end of line. 
    */ 
    private final Pattern csvPattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?:,|$)"); 
    private ArrayList<String> allMatches = null;  
    private Matcher matcher = null; 
    private String match = null; 
    private int size; 

    public CSVParser() {   
     allMatches = new ArrayList<String>(); 
     matcher = null; 
     match = null; 
    } 

    public String[] parse(String csvLine) { 
     matcher = csvPattern.matcher(csvLine); 
     allMatches.clear(); 
     String match; 
     while (matcher.find()) { 
      match = matcher.group(1); 
      if (match!=null) { 
       allMatches.add(match); 
      } 
      else { 
       allMatches.add(matcher.group(2)); 
      } 
     } 

     size = allMatches.size();  
     if (size > 0) { 
      return allMatches.toArray(new String[size]); 
     } 
     else { 
      return new String[0]; 
     }   
    } 

    public static void main(String[] args) {   
     String lineinput = "the quick,\"brown, fox jumps\",over,\"the\",,\"lazy dog\""; 

     CSVParser myCSV = new CSVParser(); 
     System.out.println("Testing CSVParser with: \n " + lineinput); 
     for (String s : myCSV.parse(lineinput)) { 
      System.out.println(s); 
     } 
    } 

} 
+0

Tôi cảm thấy như tôi nên tái lặp lại rằng điều này chỉ dành cho giải trí của tôi, không được đảm bảo để hoạt động, và chắc chắn S W KHÔNG hoạt động nếu bạn cố gắng kèm theo các dấu phân cách thoát bên trong một trong các trường của bạn. Sử dụng thư viện java csv mã nguồn mở trên sourceforge hoặc bất cứ nơi nào đó là nếu bạn cần một cái gì đó "thực". –

1

Tôi biết điều này không phải những gì OP muốn là, nhưng đối với độc giả khác, một trong những phương pháp string.Replace có thể được sử dụng để tước có dấu ngoặc kép từ mỗi phần tử trong mảng kết quả của sự Ops regex hiện hành.

+0

Điều đó cũng đúng. –

5
(?:^|,)\s*(?:(?:(?=")"([^"].*?)")|(?:(?!")(.*?)))(?=,|$) 

Điều này sẽ làm những gì bạn muốn.

Giải thích:

(?:^|,)\s* 

Các mô hình nên bắt đầu với một, hoặc đầu chuỗi. Ngoài ra, bỏ qua tất cả khoảng trắng ngay từ đầu.

lookahead và xem nếu phần còn lại bắt đầu với một báo

(?:(?=")"([^"].*?)") 

Nếu có, sau đó kết hợp không tham lam đến quote tới.

(?:(?!")(.*?)) 

Nếu nó không bắt đầu bằng dấu ngoặc kép, thì không khớp với dấu phẩy hoặc cuối chuỗi tiếp theo.

(?=,|$) 

Mẫu phải kết thúc bằng dấu phẩy hoặc cuối chuỗi.

+0

Giải pháp này làm việc cho tôi thay vì câu trả lời đã chọn, cảm ơn! –

+0

Nếu chuỗi bắt đầu bằng dấu ngoặc kép kép thì sao? Ví dụ: """,",,,,"""". (không có dấu chấm) – slodeveloper

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