2009-03-29 44 views
10

Đây là câu hỏi đầu tiên tôi muốn hỏi, nhưng trong khi nghiên cứu chi tiết cho câu hỏi tôi tìm thấy giải pháp và nghĩ rằng nó có thể được người khác quan tâm.Cụm từ thông dụng phù hợp giữa dấu ngoặc kép, có dấu ngoặc kép thoát

Trong Apache, đầy đủ yêu cầu là trong dấu ngoặc kép và bất kỳ dấu ngoặc kép bên trong luôn dấu gạch chéo ngược:

1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\" foo=bat\" HTTP/1.0" 400 299 "-" "-" "-" 

Tôi đang cố gắng để xây dựng một regex mà phù hợp với lĩnh vực chủ riêng biệt. Giải pháp hiện tại của tôi luôn luôn dừng lại trên các báo đầu tiên sau khi GET/POST (thực sự tôi chỉ cần tất cả các giá trị bao gồm kích thước chuyển giao):

^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"[^"]+"\s+(\d+)\s+(\d+|-) 

Tôi đoán tôi cũng sẽ cung cấp giải pháp của tôi từ nguồn PHP của tôi với ý kiến và định dạng tốt hơn:

$sPattern = ';^' . 
    # ip address: 1 
    '(\d+\.\d+\.\d+\.\d+)' . 
    # ident and user id 
    '\s+[^\s]+\s+[^\s]+\s+' . 
    # 2 day/3 month/4 year:5 hh:6 mm:7 ss +timezone 
    '\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]' . 
    # whitespace 
    '\s+' . 
    # request uri 
    '"[^"]+"' . 
    # whitespace 
    '\s+' . 
    # 8 status code 
    '(\d+)' . 
    # whitespace 
    '\s+' . 
    # 9 bytes sent 
    '(\d+|-)' . 
    # end of regex 
    ';'; 

Sử dụng điều này với một trường hợp đơn giản nơi URL không chứa dấu ngoặc kép khác hoạt động tốt:

1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\ foo=bat\ HTTP/1.0" 400 299 "-" "-" "-" 

Bây giờ tôi đang cố gắng để có được hỗ trợ cho không, một hoặc nhiều lần xuất hiện của \" vào nó, nhưng không thể tìm thấy một giải pháp. Sử dụng regexpal.com Tôi đã đến với điều này cho đến nay:

^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*" 

Dưới đây là chỉ là một phần thay đổi:

# request uri 
    '"(.|\\(?="))*"' . 

Tuy nhiên, nó quá tham lam. Nó ăn tất cả mọi thứ cho đến khi " cuối cùng, khi nó chỉ nên ăn cho đến khi " đầu tiên không đứng trước \. Tôi cũng đã cố gắng giới thiệu các yêu cầu mà không có \ trước " tôi muốn, nhưng nó vẫn ăn đến cuối chuỗi (Lưu ý: Tôi đã có thêm không liên quan \ ký tự để làm công việc này trong PHP):

# request uri 
    '"(.|\\(?="))*[^\\\\]"' . 

Nhưng sau đó nó đánh tôi: * ?: Nếu sử dụng ngay lập tức sau khi bất kỳ của quantifiers , +, hoặc {}, làm cho lượng hóa phi tham lam (phù hợp với số lần tối thiểu)

# request uri 
    '"(.|\\(?="))*?[^\\\\]"' . 

Các regex đầy đủ:

^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*?[^\\]"\s+(\d+)\s+(\d+|-) 

Cập nhật ngày 05 Tháng Năm 2009:

tôi phát hiện ra một lỗ hổng nhỏ trong regexp do phân tích hàng triệu dòng: nó phá vỡ trên dòng mà chứa ký tự gạch chéo ngược ngay trước đôi Trích dẫn. Nói cách khác:

...\\" 

sẽ phá vỡ regex. Apache sẽ không đăng nhập ...\" nhưng sẽ luôn luôn thoát khỏi dấu gạch chéo ngược tới \\, do đó, an toàn để giả định rằng khi có hai ký tự dấu chéo ngược trước dấu ngoặc kép.

Bất kỳ ai cũng có ý tưởng khắc phục điều này bằng regex?

nguồn lực hữu ích: the JavaScript Regexp documentation at developer.mozilla.orgregexpal.com

Trả lời

26

Hãy thử điều này:

"(?:[^\\"]+|\\.)*" 

biểu thức chính quy này phù hợp với một nhân vật dấu nháy kép theo sau là một chuỗi các hoặc bất kỳ ký tự khác ngoài \" hoặc một dãy thoát \α (trong đó α có thể là bất kỳ ký tự nào) f được theo sau bởi ký tự ngoặc kép cuối cùng. Cú pháp (?:expr) chỉ là một nhóm không chụp.

+2

Bạn có thể thêm một số thông tin khác về regex của mình vì lợi ích của tất cả không? Tôi hầu như không hiểu được những gì tôi đã viết ... cảm ơn :) – mark

+5

(?: A | B) khớp với A hoặc B. \\. phù hợp với dấu gạch chéo ngược sau bất kỳ ký tự nào ngoại trừ dòng mới. [^ \\ "] phù hợp với bất kỳ ký tự nào ngoại trừ dấu gạch chéo ngược và dấu ngoặc kép. Đặt tất cả cùng nhau thực hiện chính xác những gì bạn muốn, +1 –

+0

đẹp ... cảm ơn người đàn ông. –

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