2011-07-29 39 views
6

tôi là loại mắc kẹt cố gắng để đưa ra biểu thức chính quy để phá vỡ chuỗi với các thuộc tính sau:java regex split chuỗi

  1. Delimited bởi | (Ống) nhân vật
  2. Nếu một giá trị cá nhân chứa một đường ống, thoát với \ (backslash)
  3. Nếu một giá trị cá nhân kết thúc với dấu chéo ngược, trốn thoát với dấu chéo ngược

Vì vậy, ví dụ, đây là một số chuỗi tôi muốn chia tay:

  1. One|Two|Three nên năng suất: ["One", "Two", "Three"]
  2. One\|Two\|Three nên năng suất: ["One|Two|Three"]
  3. One\\|Two\|Three nên năng suất: ["One\", "Two|Three"]

Bây giờ làm thế nào tôi có thể chia này lên với một regex duy nhất?

CẬP NHẬT: Như nhiều bạn đã đề xuất, đây không phải là ứng dụng tốt của regex. Ngoài ra, các giải pháp regex là đơn đặt hàng của cường độ chậm hơn so với chỉ lặp qua các ký tự. Tôi đã kết thúc lặp lại các ký tự:

public static List<String> splitValues(String val) { 
    final List<String> list = new ArrayList<String>(); 
    boolean esc = false; 
    final StringBuilder sb = new StringBuilder(1024); 
    final CharacterIterator it = new StringCharacterIterator(val); 
    for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { 
     if(esc) { 
      sb.append(c); 
      esc = false; 
     } else if(c == '\\') { 
      esc = true; 
     } else if(c == '|') { 
      list.add(sb.toString()); 
      sb.delete(0, sb.length()); 
     } else { 
      sb.append(c); 
     } 
    } 
    if(sb.length() > 0) { 
     list.add(sb.toString()); 
    } 
    return list; 
} 
+1

Hãy làm cho nó rõ ràng. Những gì bạn muốn là: chia cho | và loại bỏ nó khỏi chuỗi, không chia cho \ | và loại bỏ \ từ chuỗi và cuối cùng chia cho \\ | và xóa \ | từ phần đầu tiên và \ từ phần thứ hai. Làm thế nào để bạn nghĩ rằng điều này có thể được thực hiện với một regexp? Có vẻ như hoàn cảnh khác hoàn toàn đối với tôi ... – user219882

+0

Có thể thay đổi các dấu phân cách của bạn không? – Paul

+0

Tôi nghĩ các bạn đã đúng! Điều này có thể là quá nhiều đối với regex. –

Trả lời

13

Bí quyết không được sử dụng phương pháp split(). Điều đó buộc bạn phải sử dụng một lookbehind để phát hiện các ký tự thoát, nhưng điều đó không thành công khi thoát được tự thoát (như bạn đã phát hiện ra). Bạn cần phải sử dụng find() thay vào đó, để phù hợp với tokens thay vì delimiters:

public static List<String> splitIt(String source) 
{ 
    Pattern p = Pattern.compile("(?:[^|\\\\]|\\\\.)+"); 
    Matcher m = p.matcher(source); 
    List<String> result = new ArrayList<String>(); 
    while (m.find()) 
    { 
    result.add(m.group().replaceAll("\\\\(.)", "$1")); 
    } 
    return result; 
} 

public static void main(String[] args) throws Exception 
{ 
    String[] test = { "One|Two|Three", 
        "One\\|Two\\|Three", 
        "One\\\\|Two\\|Three", 
        "One\\\\\\|Two" }; 
    for (String s :test) 
    { 
    System.out.printf("%n%s%n%s%n", s, splitIt(s)); 
    } 
} 

đầu ra:

One|Two|Three 
[One, Two, Three] 

One\|Two\|Three 
[One|Two|Three] 

One\\|Two\|Three 
[One\, Two|Three] 

One\\\|Two 
[One\|Two] 
+0

Điều đó thật ấn tượng. Bạn có thể giải thích cách hoạt động của mô hình? Tôi vẫn đấu tranh với những biểu hiện thông thường. – Paul

+0

WOW !! Nó thật ngọt ngào! Tôi biết regex có thể làm các trick :-) –

+0

Điều này hoạt động như một say mê !! Cảm ơn một lần nữa @Alan Moore !! Bây giờ làm thế nào bạn sẽ làm ngược lại? –