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 "; }';
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 "; }';
Câu trả lời:
/"(?:[^"\\]|\\.)*"/
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);
(?:...)
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.
/(["'])(?:[^\1\\]|\\.)*?\1/
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ờ.
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
\"(\\.|[^\"])*\"
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ờ.
" \"(\\\\.|[^\\\"])*\" "
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
/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/
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.
/(["\']).*?(?<!\\)(\\\\)*\1/is
sẽ hoạt động với bất kỳ chuỗi được trích dẫn nào
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:
"
;.*?
{Lazy match}; kết thúc với nhân vật không thoát[^\\]
;(.*?[^\\])??
"
), 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 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 ').
[^\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.
[^\1]
với .
một cách hiệu quả sẽ thay đổi regex này để ("|').*?\1
và 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).)*+\1
Sự. +
Là không bắt buộc nếu động cơ của bạn không hỗ trợ nó.
Một tùy chọn chưa từng được đề cập đến trước đây là:
Đ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\" match
phả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
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).
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
“
và đóng ”
)Nếu nó được tìm kiếm ngay từ đầu, có lẽ điều này có thể hoạt động?
\"((\\\")|[^\\])*\"
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.
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.