Câu trả lời:
Tôi đã sử dụng những điều sau đây rất thành công:
(["'])(?:(?=(\\?))\2.)*?\1
Nó hỗ trợ báo giá lồng nhau là tốt.
Đối với những người muốn có một lời giải thích sâu sắc hơn về cách thức hoạt động này, đây là một lời giải thích từ người dùng ephemient :
([""'])
phù hợp với một trích dẫn;((?=(\\?))\2.)
nếu dấu gạch chéo ngược tồn tại, hãy ngấu nghiến nó, và liệu điều đó có xảy ra hay không, phù hợp với một nhân vật;*?
phù hợp nhiều lần (không tham lam, như không ăn trích dẫn kết thúc);\1
phù hợp với cùng một trích dẫn đã được sử dụng để mở.
"foo\"
. Thủ thuật nhìn về phía trước làm cho bộ ?
định lượng sở hữu (ngay cả khi hương vị regex không hỗ trợ ?+
cú pháp hoặc nhóm nguyên tử)
(["'])(?:\\.|[^\\])*?\1
Nói chung, đoạn biểu thức chính quy sau đây là những gì bạn đang tìm kiếm:
"(.*?)"
Cái này dùng cái không tham lam *? toán tử để nắm bắt mọi thứ lên đến nhưng không bao gồm trích dẫn kép tiếp theo. Sau đó, bạn sử dụng một cơ chế dành riêng cho ngôn ngữ để trích xuất văn bản phù hợp.
Trong Python, bạn có thể làm:
>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
"hello \" world"
"(.*?(?<!\\))"
Tôi sẽ đi cho:
"([^"]*)"
Các [^ "] là regex cho bất kỳ nhân vật ngoại trừ ' " '
Lý do tôi sử dụng này trong phi hành nhiều tham lam là tôi phải tiếp tục tìm kiếm mà lên chỉ để chắc chắn rằng tôi nhận được nó đúng.
Hãy xem hai cách hiệu quả để đối phó với báo giá thoát. Những mẫu này không được thiết kế ngắn gọn cũng như thẩm mỹ, nhưng phải hiệu quả.
Những cách này sử dụng phân biệt ký tự đầu tiên để nhanh chóng tìm thấy các trích dẫn trong chuỗi mà không phải trả chi phí thay thế. (Ý tưởng là loại bỏ nhanh các ký tự không được trích dẫn mà không kiểm tra hai nhánh của sự xen kẽ.)
Nội dung giữa các trích dẫn được mô tả với một vòng lặp không được kiểm soát (thay vì lặp lại xen kẽ) để hiệu quả hơn: [^"\\]*(?:\\.[^"\\]*)*
Rõ ràng để đối phó với các chuỗi không có trích dẫn cân bằng, thay vào đó, bạn có thể sử dụng các bộ lượng hóa sở hữu: [^"\\]*+(?:\\.[^"\\]*)*+
hoặc một cách giải quyết để mô phỏng chúng, để ngăn chặn quá nhiều việc quay lại. Bạn cũng có thể chọn một phần trích dẫn có thể là một trích dẫn mở đầu cho đến khi trích dẫn tiếp theo (không thoát) hoặc kết thúc chuỗi. Trong trường hợp này không cần sử dụng các bộ định lượng sở hữu, bạn chỉ cần thực hiện trích dẫn cuối cùng là tùy chọn.
Lưu ý: đôi khi các trích dẫn không được thoát bằng dấu gạch chéo ngược mà bằng cách lặp lại trích dẫn. Trong trường hợp này, mô hình con nội dung trông như thế này:[^"]*(?:""[^"]*)*
Các mô hình tránh sử dụng một nhóm chụp và phản xạ (ý tôi là một cái gì đó giống như (["']).....\1
) và sử dụng một sự thay thế đơn giản nhưng với ["']
lúc đầu, về yếu tố.
Perl thích:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(lưu ý rằng đó (?s:...)
là đường cú pháp để bật chế độ dotall / singleline bên trong nhóm không bắt giữ. Nếu cú pháp này không được hỗ trợ, bạn có thể dễ dàng bật chế độ này cho tất cả các mẫu hoặc thay thế dấu chấm bằng [\s\S]
)
(Cách viết mẫu này hoàn toàn "điều khiển bằng tay" và không tính đến các tối ưu hóa bên trong động cơ cuối cùng)
Kịch bản ECMA:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
POSIX mở rộng:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
hoặc đơn giản:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
/pattern/
mà không thoát bất cứ thứ gì (thay vì ký hiệu đối tượng new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
)
s
ở đây: (?s:
và nếu bạn đặt (?s)
ở đâu đó trong mẫu.
RegEx của câu trả lời được chấp nhận trả về các giá trị bao gồm cả dấu ngoặc kép của chúng: "Foo Bar"
và "Another Value"
là khớp.
Dưới đây là RegEx chỉ trả về các giá trị giữa các dấu ngoặc kép (như người hỏi đã yêu cầu):
Chỉ trích dẫn kép (giá trị sử dụng của nhóm chụp số 1):
"(.*?[^\\])"
Chỉ trích dẫn duy nhất (giá trị sử dụng của nhóm chụp số 1):
'(.*?[^\\])'
Cả hai (giá trị sử dụng của nhóm chụp số 2):
(["'])(.*?[^\\])\1
-
Tất cả các hỗ trợ thoát và trích dẫn lồng nhau.
src="(.*)"
nhưng rõ ràng là nó đã chọn mọi thứ trước lần cuối ", mặc dù vậy, REGEX của bạn chỉ chọn nội dung src =" ", nhưng tôi không hiểu làm thế nào?
Đặc biệt, không có câu trả lời nào trong số này tạo ra một biểu thức chính trong đó kết quả trả về là văn bản bên trong dấu ngoặc kép, đó là những gì được yêu cầu. MA-Madden cố gắng nhưng chỉ nhận được trận đấu bên trong như một nhóm bị bắt chứ không phải toàn bộ trận đấu. Một cách để thực sự làm điều đó sẽ là:
(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
Ví dụ cho điều này có thể được nhìn thấy trong bản demo này https://regex101.com/r/Hbj8aP/1
Chìa khóa ở đây là cái nhìn tích cực ở đầu (cái ?<=
) và cái nhìn tích cực ở cuối (cái ?=
). Lookbehind đang nhìn phía sau nhân vật hiện tại để kiểm tra báo giá, nếu tìm thấy thì bắt đầu từ đó và sau đó lookahead đang kiểm tra nhân vật phía trước để báo giá và nếu tìm thấy dừng lại trên nhân vật đó. Nhóm lookbehind (the ["']
) được bọc trong ngoặc để tạo một nhóm cho bất kỳ trích dẫn nào được tìm thấy khi bắt đầu, điều này sau đó được sử dụng ở cuối lookahead (?=\1)
để đảm bảo nó chỉ dừng lại khi tìm thấy trích dẫn tương ứng.
Điều phức tạp duy nhất khác là bởi vì giao diện không thực sự tiêu thụ trích dẫn cuối, nó sẽ được tìm thấy một lần nữa bởi giao diện bắt đầu khiến văn bản giữa kết thúc và bắt đầu trích dẫn trên cùng một dòng được khớp. Đặt một ranh giới từ trên trích dẫn mở đầu ( ["']\b
) sẽ giúp ích cho việc này, mặc dù lý tưởng là tôi muốn di chuyển qua cái nhìn nhưng tôi không nghĩ rằng điều đó là có thể. Bit cho phép các nhân vật trốn thoát ở giữa tôi đã lấy trực tiếp từ câu trả lời của Adam.
Mô hình (["'])(?:(?=(\\?))\2.)*?\1
ở trên thực hiện công việc nhưng tôi lo ngại về hiệu suất của nó (nó không tệ nhưng có thể tốt hơn). Của tôi dưới nó nhanh hơn ~ 20%.
Các mô hình "(.*?)"
chỉ là không đầy đủ. Lời khuyên của tôi cho mọi người đọc đây chỉ là KHÔNG SỬ DỤNG NÓ !!!
Chẳng hạn, nó không thể bắt được nhiều chuỗi (nếu cần tôi có thể cung cấp một trường hợp thử nghiệm toàn diện) như chuỗi dưới đây:
$ string = 'Bạn có khỏe không? Tôi
\'
khỏe, cảm ơn bạn ';
Phần còn lại của họ chỉ là "tốt" như ở trên.
Nếu bạn thực sự quan tâm cả về hiệu suất và độ chính xác thì hãy bắt đầu với cách dưới đây:
/(['"])((\\\1|.)*?)\1/gm
Trong các thử nghiệm của tôi, nó bao gồm mọi chuỗi tôi đã gặp nhưng nếu bạn tìm thấy thứ gì đó không hoạt động, tôi sẵn sàng cập nhật nó cho bạn.
Kiểm tra mô hình của tôi trong một thử nghiệm regex trực tuyến .
Tôi thích giải pháp của Eugen Mihailescu để khớp nội dung giữa các trích dẫn trong khi cho phép thoát dấu ngoặc kép. Tuy nhiên, tôi đã phát hiện ra một số vấn đề với việc thoát và đưa ra biểu thức chính sau để khắc phục chúng:
(['"])(?:(?!\1|\\).|\\.)*\1
Nó thực hiện các mẹo và vẫn còn khá đơn giản và dễ bảo trì.
Bản demo (với một số trường hợp thử nghiệm hơn; hãy sử dụng và mở rộng trên đó).
PS: Nếu bạn chỉ muốn nội dung giữa các trích dẫn trong toàn bộ trận đấu ( $0
) và không sợ sử dụng hình phạt hiệu suất:
(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
Thật không may, không có dấu ngoặc kép là neo, tôi đã phải thêm một ranh giới \b
không chơi tốt với các khoảng trắng và các ký tự ranh giới không từ sau trích dẫn bắt đầu.
Hoặc, sửa đổi phiên bản ban đầu bằng cách thêm một nhóm và trích xuất dạng chuỗi$2
:
(['"])((?:(?!\1|\\).|\\.)*)\1
PPS: Nếu bạn chỉ tập trung vào hiệu quả, hãy đi với giải pháp của Casimir et Hippolyte ; Đó là một điều tốt.
-
, như trong tọa độ kinh độ.
Phiên bản này
kiểm soát quay lui
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
TRẢ LỜI THÊM! Đây là giải pháp tôi đã sử dụng
\"([^\"]*?icon[^\"]*?)\"
TLDR;
thay thế biểu tượng từ bằng những gì bạn đang tìm kiếm trong dấu ngoặc kép và voila!
Cách thức hoạt động này là tìm kiếm từ khóa và không quan tâm đến những gì khác ở giữa các trích dẫn. EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
regex tìm kiếm một dấu ngoặc kép "
sau đó nó tìm kiếm bất kỳ nhóm chữ cái nào có thể không tồn tại "
cho đến khi nó tìm thấy icon
và bất kỳ nhóm chữ cái nào có thể không phải là "
nó sẽ tìm cách đóng"
name="value"
bằng name={"value"}
vì trả về regex của câu trả lời này icon
/ value
là nhóm thứ hai (không giống như câu trả lời được chấp nhận). Tìm : =\"([^\"]*?[^\"]*?)\"
Thay thế :={"$1"}
Tôi thích phiên bản mở rộng hơn của Axeman, nhưng đã gặp một số rắc rối với nó (ví dụ như nó không phù hợp
foo "string \\ string" bar
hoặc là
foo "string1" bar "string2"
chính xác, vì vậy tôi đã cố gắng sửa nó:
# opening quote
(["'])
(
# repeat (non-greedy, so we don't span multiple strings)
(?:
# anything, except not the opening quote, and not
# a backslash, which are handled separately.
(?!\1)[^\\]
|
# consume any double backslash (unnecessary?)
(?:\\\\)*
|
# Allow backslash to escape characters
\\.
)*?
)
# same character as opening quote
\1
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)
Chỉ cần thử điều này, hoạt động như một nét duyên dáng !!!
\
bỏ qua ký tự
" foo bar" "loloo"
. Tôi nghi ngờ bạn có nghĩa là bọc nó trong một chuỗi thô như bạn đã làm với regex : r'"\" foo bar\" \"loloo\""'
. Vui lòng sử dụng các khả năng định dạng tuyệt vời của SO bất cứ khi nào phù hợp. Đó không chỉ là mỹ phẩm; chúng tôi thực sự không thể nói bạn đang cố nói gì nếu bạn không sử dụng chúng. Và chào mừng bạn đến với Stack Overflow !
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
Điều này sẽ dẫn đến:> Foo Bar <> <> nhưng điều này <
Ở đây tôi đã chỉ ra chuỗi kết quả giữa> <'s cho rõ ràng, cũng sử dụng phiên bản không tham lam với lệnh sed này, trước tiên chúng ta vứt rác trước và sau đó "" và sau đó thay thế nó bằng phần giữa "" và bao quanh điều này bởi> <'s.
Từ Greg H. tôi đã có thể tạo regex này cho phù hợp với nhu cầu của mình.
Tôi cần phải khớp một giá trị cụ thể đủ tiêu chuẩn bằng cách nằm trong dấu ngoặc kép. Nó phải là một trận đấu đầy đủ, không có trận đấu một phần nào có thể kích hoạt một cú đánh
ví dụ: "test" không thể khớp với "test2".
reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
print "winning..."
thợ săn
Nếu bạn đang cố gắng tìm các chuỗi chỉ có một hậu tố nhất định, chẳng hạn như cú pháp dấu chấm, bạn có thể thử điều này:
\"([^\"]*?[^\"]*?)\".localized
Trong trường hợp .localized
là hậu tố.
Thí dụ:
print("this is something I need to return".localized + "so is this".localized + "but this is not")
Nó sẽ chụp "this is something I need to return".localized
và "so is this".localized
không "but this is not"
.
Một câu trả lời bổ sung cho tập hợp con của các lập trình viên Microsoft VBA chỉ có một người sử dụng thư viện Microsoft VBScript Regular Expressions 5.5
và điều này đưa ra mã sau đây
Sub TestRegularExpression()
Dim oRE As VBScript_RegExp_55.RegExp '* Tools->References: Microsoft VBScript Regular Expressions 5.5
Set oRE = New VBScript_RegExp_55.RegExp
oRE.Pattern = """([^""]*)"""
oRE.Global = True
Dim sTest As String
sTest = """Foo Bar"" ""Another Value"" something else"
Debug.Assert oRE.test(sTest)
Dim oMatchCol As VBScript_RegExp_55.MatchCollection
Set oMatchCol = oRE.Execute(sTest)
Debug.Assert oMatchCol.Count = 2
Dim oMatch As Match
For Each oMatch In oMatchCol
Debug.Print oMatch.SubMatches(0)
Next oMatch
End Sub
Đối với tôi đã làm việc này:
|([\'"])(.*?)\1|i
Tôi đã sử dụng một câu như thế này:
preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
và nó đã làm việc rất tốt
Tất cả các câu trả lời ở trên là tốt .... ngoại trừ họ KHÔNG hỗ trợ tất cả các ký tự unicode! tại ECMA Script (Javascript)
Nếu bạn là người dùng Node, bạn có thể muốn phiên bản sửa đổi của câu trả lời được chấp nhận hỗ trợ tất cả các ký tự unicode:
/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
Hãy thử ở đây .
? The preceding token is not quantifiable