Regex cho chuỗi được trích dẫn có dấu ngoặc kép thoát


122

Làm cách nào để lấy chuỗi con " It's big \"problem "bằng biểu thức chính quy?

s = ' function(){  return " It\'s big \"problem  ";  }';     

1
Làm thế nào để bạn tìm thấy "Nó" trong một chuỗi chỉ chứa "Là"? Tôi muốn sửa nó cho bạn, nhưng tôi không biết quy ước trích dẫn đơn / thoát nào áp dụng cho ngôn ngữ bạn đang sử dụng.
Jonathan Leffler


2
Thực ra, nhìn vào ngày tháng, tôi thấy câu hỏi kia trùng lặp với câu hỏi này. Dù bằng cách nào, hãy chắc chắn kiểm tra câu trả lời của tôi .
ridgerunner

@ridgerunner: Tôi đang bỏ phiếu để đóng điều này theo đề xuất của bạn. Đúng là câu hỏi khác gần đây hơn, nhưng nó cũng hay hơn nhiều (chủ yếu là nhờ câu trả lời của bạn).
Alan Moore

Câu trả lời:


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

Hoạt động trong The Regex Coach và PCRE Workbench.

Ví dụ về thử nghiệm trong JavaScript:

    var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
    var m = s.match(/"(?:[^"\\]|\\.)*"/);
    if (m != null)
        alert(m);


24
Có ý nghĩa. Tiếng Anh thuần túy: Hai dấu ngoặc kép bao quanh không hoặc nhiều hơn "bất kỳ ký tự nào không phải là dấu ngoặc kép hoặc dấu gạch chéo ngược" hoặc "dấu gạch chéo ngược theo sau bởi bất kỳ ký tự nào". Tôi không thể tin rằng tôi đã không nghĩ rằng để làm điều đó ...
Ajedi32

7
Tôi sẽ tự trả lời. =) (?:...)là nhóm thụ động hoặc không bắt bài. Nó có nghĩa là nó không thể được tham chiếu lại sau này.
magras

sau khi tìm kiếm rất nhiều và thử nghiệm rất nhiều đây là giải pháp thực sự và duy nhất tôi tìm thấy cho vấn đề phổ biến này. Cảm ơn!
Cancerbero

10
cảm ơn vì điều đó. tôi cũng muốn khớp các dấu ngoặc kép nên tôi đã điều chỉnh nó cho phù hợp với điều này:/(["'])(?:[^\1\\]|\\.)*?\1/
leo

Với var s = ' my \\"new\\" string and \"this should be matched\"';, cách tiếp cận này sẽ dẫn đến kết quả bất ngờ.
Wiktor Stribiżew

32

Cái này đến từ nanorc.sample có sẵn trong nhiều bản phân phối linux. Nó được sử dụng để làm nổi bật cú pháp của chuỗi kiểu C

\"(\\.|[^\"])*\"

Với var s = ' my \\"new\\" string and \"this should be matched\"';, cách tiếp cận này sẽ dẫn đến kết quả bất ngờ.
Wiktor Stribiżew

1
c.nanorc là nơi đầu tiên tôi đến. Không thể lấy nó để làm việc như là một phần của một chữ C chuỗi cho đến khi đôi thoát tất cả mọi thứ như thế này" \"(\\\\.|[^\\\"])*\" "
hellork

Điều này hoạt động với các hàm egrep và re_comp / re_exec từ libc.
fk0

19

Như được cung cấp bởi ePharaoh, câu trả lời là

/"([^"\\]*(\\.[^"\\]*)*)"/

Để áp dụng những điều trên cho chuỗi được trích dẫn đơn hoặc được trích dẫn kép, hãy sử dụng

/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/

2
Đây là tập hợp duy nhất phù hợp với tôi với một chuỗi trích dẫn lớn 1,5 KB duy nhất chứa 99 lần thoát. Mọi biểu thức khác trên trang này đều bị lỗi trong trình soạn thảo văn bản của tôi với lỗi tràn. Mặc dù hầu hết ở đây đều hoạt động trong trình duyệt, nhưng bạn cần lưu ý điều này. Fiddle: jsfiddle.net/aow20y0L
Beejor

3
Xem câu trả lời của @ MarcAndrePoulin bên dưới để giải thích.
ăn trưa

10

Hầu hết các giải pháp được cung cấp ở đây sử dụng các đường dẫn lặp lại thay thế, tức là (A | B) *.

Bạn có thể gặp phải lỗi tràn ngăn xếp trên các đầu vào lớn vì một số trình biên dịch mẫu thực hiện điều này bằng cách sử dụng đệ quy.

Java chẳng hạn: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993

Một cái gì đó như thế này: "(?:[^"\\]*(?:\\.)?)*"hoặc cái được cung cấp bởi Guy Bedford sẽ giảm số lượng các bước phân tích cú pháp tránh hầu hết các lần tràn ngăn xếp.


9
"(?:\\"|.)*?"

Xen kẽ các dấu \".chuyển qua các dấu ngoặc kép trong khi bộ định lượng lười *?đảm bảo rằng bạn không đi qua phần cuối của chuỗi được trích dẫn. Hoạt động với các lớp .NET Framework RE


Nhưng thất bại với"\\"
Ian


/"(?:(?:\\"|[^"])*)"/gđiều này sẽ được khắc phục
dave

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

Lấy trực tiếp từ man perlrehệ thống Linux có cài đặt Perl 5.22.0. Như một sự tối ưu hóa, regex này sử dụng dạng 'posessive' của cả hai +*để ngăn chặn việc bẻ khóa ngược, vì đã biết trước rằng một chuỗi không có dấu ngoặc kép sẽ không khớp trong mọi trường hợp.


4
/(["\']).*?(?<!\\)(\\\\)*\1/is

sẽ hoạt động với bất kỳ chuỗi được trích dẫn nào


1
Đẹp, nhưng quá linh hoạt so với yêu cầu (sẽ phù hợp với các dấu ngoặc kép ...). Và có thể được đơn giản hóa thành /".*?(?<!\)"/ trừ khi tôi bỏ lỡ điều gì đó. Ồ, và một số ngôn ngữ (ví dụ: JavaScript) không hiểu được các biểu thức nhìn sau tiêu cực.
PhiLho 30/10/08

1
@PhiLho, chỉ sử dụng một (? <! \\) duy nhất sẽ không thành công với dấu gạch chéo ngược thoát ở cuối chuỗi. Mặc dù vậy, đúng về vẻ ngoài trong JavaScript.
Markus Jarderot

4

Cái này hoạt động hoàn hảo trên PCRE và không rơi vào StackOverflow.

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

Giải trình:

  1. Mọi chuỗi được trích dẫn đều bắt đầu bằng Char: " ;
  2. Nó có thể chứa bất kỳ số ký tự nào: .*?{Lazy match}; kết thúc với nhân vật không thoát[^\\] ;
  3. Câu lệnh (2) là tùy chọn Lazy (!) Vì chuỗi có thể trống (""). Vì thế:(.*?[^\\])??
  4. Cuối cùng, mọi chuỗi được trích dẫn đều kết thúc bằng Char ( "), nhưng nó có thể được đặt trước bằng số cặp dấu thoát chẵn (\\\\)+; và nó là tùy chọn Greedy (!): ((\\\\)+)?+{Greedy so khớp}, chuỗi phụ có thể trống hoặc không có cặp kết thúc!

Đây không phải là mô hình hiệu quả nhất trên thế giới, nhưng ý tưởng này rất thú vị. Lưu ý rằng bạn có thể rút ngắn nó như thế này:"(.*?[^\\])?(\\\\)*"
Casimir et Hippolyte

2

đây là một cái hoạt động với cả "và" và bạn dễ dàng thêm những cái khác khi bắt đầu.

("| ') (?: \\\ 1 | [^ \ 1]) *? \ 1

nó sử dụng backreference (\ 1) so khớp chính xác với những gì nằm trong nhóm đầu tiên ("hoặc ').

http://www.regular-expressions.info/backref.html


đây là một giải pháp rất tốt, nhưng [^\1]nên được thay thế bằng .vì không có cái gọi là tham chiếu chống ngược và dù sao thì nó cũng không thành vấn đề. điều kiện đầu tiên sẽ luôn phù hợp trước khi bất kỳ điều gì xấu có thể xảy ra.
Reed

@SephReed - thay thế [^\1]với .một cách hiệu quả sẽ thay đổi regex này để ("|').*?\1và sau đó nó sẽ phù hợp "foo\"trong "foo \" bar". Điều đó nói rằng, bắt tay [^\1]vào làm việc thực sự rất khó. @ Mathiashansen - Bạn nên với cồng kềnh và tốn kém (?!\1).(vì vậy toàn bộ regex, với một số ngẫu nhiên hiệu quả, sẽ là (["'])(?:\\.|(?!\1).)*+\1Sự. +Là không bắt buộc nếu động cơ của bạn không hỗ trợ nó.
Adam Katz

2

Một tùy chọn chưa từng được đề cập đến trước đây là:

  1. Đảo ngược chuỗi.
  2. Thực hiện khớp trên chuỗi đảo ngược.
  3. Đảo ngược các chuỗi đã khớp.

Điều này có thêm phần thưởng là có thể đối sánh chính xác các thẻ mở đã thoát.

Giả sử bạn có chuỗi sau; String \"this "should" NOT match\" and "this \"should\" match" Ở đây, \"this "should" NOT match\"không nên khớp và "should"nên được. Trên hết this \"should\" matchphải phù hợp và\"should\" không nên.

Đầu tiên là một ví dụ.

// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';

// The RegExp.
const regExp = new RegExp(
    // Match close
    '([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
    '((?:' +
        // Match escaped close quote
        '(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
        // Match everything thats not the close quote
        '(?:(?!\\1).)' +
    '){0,})' +
    // Match open
    '(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
    'g'
);

// Reverse the matched strings.
matches = myString
    // Reverse the string.
    .split('').reverse().join('')
    // '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'

    // Match the quoted
    .match(regExp)
    // ['"hctam "\dluohs"\ siht"', '"dluohs"']

    // Reverse the matches
    .map(x => x.split('').reverse().join(''))
    // ['"this \"should\" match"', '"should"']

    // Re order the matches
    .reverse();
    // ['"should"', '"this \"should\" match"']

Được rồi, bây giờ để giải thích về RegExp. Đây là regexp có thể dễ dàng bị bẻ thành ba mảnh. Như sau:

# Part 1
(['"])         # Match a closing quotation mark " or '
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)
# Part 2
((?:          # Match inside the quotes
(?:           # Match option 1:
  \1          # Match the closing quote
  (?=         # As long as it's followed by
    (?:\\\\)* # A pair of escape characters
    \\        # 
    (?![\\])  # As long as that's not followed by an escape
  )           # and a single escape
)|            # OR
(?:           # Match option 2:
  (?!\1).     # Any character that isn't the closing quote
)
)*)           # Match the group 0 or more times
# Part 3
(\1)           # Match an open quotation mark that is the same as the closing one
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)

Điều này có thể rõ ràng hơn rất nhiều ở dạng hình ảnh: được tạo bằng cách sử dụng Regulex của Jex

Hình ảnh trên github (JavaScript Trình hiển thị biểu thức chính quy.) Xin lỗi, tôi không có đủ uy tín để đưa hình ảnh vào, vì vậy, hiện tại nó chỉ là một liên kết.

Đây là ý chính của một hàm ví dụ sử dụng khái niệm này nâng cao hơn một chút: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js


0

Người ta phải nhớ rằng regexps không phải là một viên đạn bạc cho mọi thứ chuỗi-y. Một số công cụ đơn giản hơn để thực hiện với con trỏ và tuyến tính, thủ công, tìm kiếm. Một CFL sẽ thực hiện thủ thuật này khá đơn giản, nhưng không có nhiều triển khai CFL (afaik).


3
Đúng vậy, nhưng vấn đề này nằm trong khả năng của regexes, và có rất nhiều cách triển khai chúng.
Alan Moore

0

Một phiên bản mở rộng hơn của https://stackoverflow.com/a/10786066/1794894

/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/   

Phiên bản này cũng chứa

  1. Độ dài trích dẫn tối thiểu là 50
  2. Loại dấu ngoặc kép bổ sung (mở và đóng )

0

Lộn xộn tại regexpal và kết thúc với regex này: (Đừng hỏi tôi cách nó hoạt động, tôi hầu như không hiểu ngay cả khi tôi đã viết nó lol)

"(([^"\\]?(\\\\)?)|(\\")+)+"

0

Nếu nó được tìm kiếm ngay từ đầu, có lẽ điều này có thể hoạt động?

\"((\\\")|[^\\])*\"

0

Tôi đã gặp phải sự cố tương tự khi cố gắng xóa các chuỗi được trích dẫn có thể cản trở việc phân tích cú pháp của một số tệp.

Tôi đã kết thúc với một giải pháp hai bước đánh bại mọi regex phức tạp mà bạn có thể đưa ra:

 line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
 line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful

Dễ đọc hơn và có lẽ hiệu quả hơn.


0

Nếu IDE của bạn là IntelliJ Idea, bạn có thể quên tất cả những vấn đề đau đầu này và lưu trữ regex của bạn vào một biến Chuỗi và khi bạn sao chép-dán nó vào bên trong dấu ngoặc kép, nó sẽ tự động chuyển sang định dạng regex được chấp nhận.

ví dụ trong Java:

String s = "\"en_usa\":[^\\,\\}]+";

bây giờ bạn có thể sử dụng biến này trong regexp của mình hoặc ở bất kỳ đâu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.