RegEx: Değerleri tırnak işaretleri arasına alma


Yanıtlar:


361

Aşağıdakileri büyük bir başarıyla kullanıyorum:

(["'])(?:(?=(\\?))\2.)*?\1

İç içe tırnakları da destekler.

Bunun nasıl çalıştığına dair daha ayrıntılı bir açıklama yapmak isteyenler için, kullanıcı ephemient'inden bir açıklama :

([""'])bir teklifle eşleşir; ((?=(\\?))\2.)ters eğik çizgi varsa, silip süpürün ve bunun olup olmadığını bir karakterle eşleştirin; *?birçok kez eşleşir (açgözlülükle, kapanış teklifini yememek için); \1açılış için kullanılan aynı teklif ile eşleşir.


6
@steve: bu da yanlış eşleşir "foo\". İleriye bakma hilesi, ?nicelleştiriciyi sahipleniyor (regex lezzeti ?+sözdizimini veya atom gruplamasını desteklemese bile )
Robin

1
Python ile bu bir hata oluşturur: sre_constants.error: açık gruba atıfta bulunamaz
a1an

9
Bu, eşleşen tırnak işaretlerini içeren değerleri döndürür. Talep edildiği gibi yalnızca teklifler arasında içerik döndürme şansı yok mu?
Martin Schneider

4
Bir ilerlemeyi iyelikçi bir niceleyici olarak kötüye kullanmak tamamen gereksiz ve kafa karıştırıcıdır. Sadece bir alternatif kullanın:(["'])(?:\\.|[^\\])*?\1
Aran-Fey

2
boş dizeleri önlemek nasıl?
Vikas Bansal

333

Genel olarak, aşağıdaki düzenli ifade parçası aradığınız şeydir:

"(.*?)"

Bu açgözlü olmayan * kullanır? Operatör bir sonraki çift tırnak dahil olmak üzere kadar her şeyi yakalamak için. Ardından, eşleşen metni ayıklamak için dile özgü bir mekanizma kullanırsınız.

Python'da şunları yapabilirsiniz:

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']

11
Bu harika, ancak kaçan tırnaklarla dizeleri işlemez. örneğin"hello \" world"
robbyt

JavaScript eşleşmesini kullandığınızda, tırnak işaretleri de aynı olur. Burada açıklandığı gibi exec üzerinden yineleme ile çalışacaktır: stackoverflow.com/questions/7998180/…
Kiechlus

4
@robbyt Yanıt için biraz geç olduğunu biliyorum, ama olumsuz bir görüşe ne dersin? "(.*?(?<!\\))"
Mateus

4
Teşekkür ederim - başa çıkmak için kaçan tırnak olmadığından eminseniz bu daha basittir.
squarecandy

Bir kelime. Harika!
Shiva Avula

89

Ben giderdim:

"([^"]*)"

[^ "] Dışında herhangi karakter için düzenli ifade olan ' " '
ı olmayan açgözlü birçok operatör üzerinden bu kullanmak nedenle sadece emin bunu düzeltmek olsun yapmak için o kadar aramaya devam etmek zorunda olmasıdır.


1
Bu, farklı regex yorumları arasında da iyi davranır.
Phil Bennett

5
Bu benim akıl sağlığımı kurtardı. RegEx .NET uygulamasında, "(. *?)" İstenen etkiye sahip değildir (açgözlü davranmaz), ancak "([^"] *) "yapar.
Jens Neubauer

Bu en iyi cevap imo. Teşekkürler
Lmao 123

28

Kaçan alıntılarla başa çıkmanın iki etkili yolunu görelim. Bu kalıplar kısa ve estetik olarak değil, verimli olacak şekilde tasarlanmıştır.

Bu yollar, bir alternatifin maliyeti olmadan dizede tırnak işaretleri bulmak için ilk karakter ayrımını kullanır. (Fikir, değişimin iki dalını test etmeden tırnak işareti olmayan karakterleri hızlı bir şekilde atmaktır.)

Teklifler arasındaki içerik, daha verimli olması için kaydedilmemiş bir döngü (tekrarlanan bir dönüşüm yerine) ile açıklanır: [^"\\]*(?:\\.[^"\\]*)*

Açıkça dengeli tırnak işareti olmayan dizelerle uğraşmak için, bunun yerine iyelik niceleyicileri kullanabilirsiniz: [^"\\]*+(?:\\.[^"\\]*)*+ya da çok fazla geri izlemeyi önlemek için bunları taklit etmek için bir geçici çözüm. Alıntılanan bir parçanın bir sonraki (kaçan olmayan) alıntıya veya dizenin sonuna kadar bir açılış alıntısı olmasını da seçebilirsiniz. Bu durumda, iyelik niceliklerini kullanmaya gerek yoktur, sadece son alıntıyı isteğe bağlı yapmanız gerekir.

Uyarı: bazen tırnak işaretleri ters eğik çizgi ile değil, tekrarı tekrarlayarak kaçar. Bu durumda, içerik alt deseni şöyle görünür:[^"]*(?:""[^"]*)*

Modeller bir yakalama grubunun ve bir geri başvurunun kullanılmasını önler (yani bir şey demek istiyorum (["']).....\1) ve basit bir değişim kullanır, ancak ["']başlangıçta faktörle birlikte.

Perl gibi:

["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')

( (?s:...)yakalamayan grup içinde dotall / singleline modunu açmak için sözdizimsel bir şeker olduğuna dikkat edin . Bu sözdizimi desteklenmiyorsa, tüm desen için bu modu kolayca açabilir veya noktayı değiştirebilirsiniz [\s\S])

(Bu kalıbın yazılma şekli tamamen "elle çalıştırılır" ve nihai motor dahili optimizasyonlarını dikkate almaz)

ECMA betiği:

(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')

POSIX genişletildi:

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

ya da sadece:

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

1
Python ECMA betiğini ham dize biçiminde kabul eder, yani r "" "ECMA betiği" ""
a1an

1
Bu harika bir şey, ECMA'nızı kaçan yeni satır ve çift tırnak içinde satır başı ile çalışmak üzere uyarlamak çok kolaydı.
Douglas Gaskell

@ douglasg14b: Teşekkürler. Not JavaScript kullanmak istiyorsanız, sadece edebi notasyonu kullanmak gerektiğini /pattern/(yerine nesne gösterimi bir şey kaçan olmadan new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");)
Casimir et Hippolyte

@ a1an: evet, ancak sburada kaldırırsanız ve desende bir yere (?s:koyarsanız Perl sürümünü kullanabilirsiniz (?s).
Casimir et Hippolyte

16

Kabul edilen yanıtın RegEx değeri, ek tırnak işaretleri: "Foo Bar"ve "Another Value"eşleşmeler olarak dahil değerleri döndürür .

Yalnızca tırnak işaretleri arasındaki değerleri döndüren (sorgulayıcının istediği gibi) RegEx şunlardır :

Yalnızca çift tırnak (1 numaralı yakalama grubunun değerini kullanın):

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

Yalnızca tek tırnak (1 numaralı yakalama grubunun değerini kullanın):

'(.*?[^\\])'

Her ikisi de (yakalama grubu # 2 değerini kullanın):

(["'])(.*?[^\\])\1

-

Tüm destek kaçtı ve iç içe tırnak.


Lütfen, bu neden işe yarıyor? Ben kullanıyordum src="(.*)"ama geçen 'içeriği" senin REGEX, olsa da, = yalnızca src seçilen' önce belli ki her şeyi seçerek, ama ben anlamadım nasıl?
Lucas Bustamante

Ben basitlik için bu bir çok seviyorum ama keşfettiğim gibi tırnak arasında boş ya da hiçbir değer işlemez
RedactedProfile

16

Tuhaf bir şekilde, bu cevapların hiçbiri, döndürülen eşleşmenin tırnak içindeki metin olduğu regex üretmez, bu da istenir. MA-Madden dener, ancak iç maçı tüm maçtan ziyade yakalanan bir grup olarak alır. Aslında bunu yapmanın bir yolu:

(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)

Bunun örnekleri bu demoda görülebilir https://regex101.com/r/Hbj8aP/1

Buradaki anahtar, başlangıçtaki ?<=pozitif bakış açısı (the ) ve sondaki pozitif bakış açısı (the ?=). Gözetleme, bir teklif olup olmadığını kontrol etmek için mevcut karakterin arkasına bakıyor, eğer o zaman oradan başlayın ve sonra ileriye doğru bir teklif için karakteri kontrol ediyor ve bulunursa o karakterde duruyor. Yeniden inceleme grubu ( ["']), başlangıçta hangi alıntı bulunduğuna ilişkin bir grup oluşturmak için parantez içine alınır, bu daha sonra (?=\1)yalnızca ilgili alıntıyı bulduğunda durduğundan emin olmak için sonunda ileriye doğru kullanılır .

Diğer tek sorun, ileriye doğru son alıntıyı kullanmadığı için, aynı satırdaki bitiş ve başlangıç ​​tırnakları arasındaki metnin eşleşmesine neden olan başlangıç ​​bakış arkası tarafından tekrar bulunacaktır. ["']\bİdeal olarak, ileriye doğru ilerlemek istiyorum, ancak bunun mümkün olduğunu düşünmüyorum, ancak açılış teklifine ( ) bir kelime sınırı koymak bu konuda yardımcı olur. Ortadaki kaçan karakterlere izin veren biraz, doğrudan Adam'ın cevabından aldım.



8

Yukarıdaki desen (["'])(?:(?=(\\?))\2.)*?\1işi yapıyor ancak performanslarından endişeliyim (kötü değil ama daha iyi olabilir). Benimki ~% 20 daha hızlı.

Desen "(.*?)"tamamlanmadı. Bu okuma herkes için benim tavsiyem sadece KULLANMAYIN !!!

Örneğin, aşağıdaki gibi birçok dizeyi yakalayamaz (gerekirse kapsamlı bir test durumu sağlayabilirim):

$ string = 'Nasılsın? Ben \'iyiyim, teşekkür ederim ';

Geri kalanı da yukarıdaki gibi "iyi" dir.

Hem performansı hem de hassasiyeti gerçekten önemsiyorsanız, aşağıdaki ile başlayın:

/(['"])((\\\1|.)*?)\1/gm

Testlerimde tanıştığım her dizeyi kapsıyordu, ancak işe yaramayan bir şey bulursanız memnuniyetle sizin için güncelleyeceğim.

Çevrimiçi regex test cihazında desenimi kontrol et .


1
Deseninizin sadeliğini seviyorum, ancak performans açısından Casimir et Hippolyte'nin deseni tüm genişletilmiş çözümleri sudan dışarı atıyor. Ayrıca, deseninizin cümlenin sonunda kaçan bir alıntı gibi genişletilmiş kenar durumlarıyla ilgili sorunları var gibi görünüyor.
wp78de

7

Eugen Mihailescu'nun tırnak işaretleri arasındaki içeriğe uygun çözümünü , tırnaklardan kaçmaya izin verirken beğendim . Ancak, kaçmakla ilgili bazı problemler keşfettim ve bunları düzeltmek için aşağıdaki normal ifadeyi buldum:

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

Hile yapar ve hala oldukça basit ve bakımı kolaydır.

Demo (bazı test senaryolarıyla; kullanmaktan ve genişletmekten çekinmeyin).


Not: Sadece içerik istiyorsanız arasındaki tam maçında (içinde tırnak $0) ve performans cezası kullanım korkmuyoruz:

(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)

Ne yazık ki, tırnakları tırnaklar olmadan \b, başlangıç ​​alıntısından sonra boşluklarla ve sözcük olmayan sınır karakterleriyle iyi oynamayan bir sınır eklemek zorunda kaldım .

Alternatif olarak, bir grup$2 ekleyerek ilk sürümü değiştirin ve dize formunu çıkarın :

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

PPS: Odak noktanız sadece verimlilik üzerindeyse, Casimir et Hippolyte'nin çözümüyle devam edin ; iyi bir tane.


gözlem: ikinci normal ifade -, boylam koordinatlarında olduğu gibi eksi işaretli bir değeri kaçırır .
Crowcoder

Hiçbir şeyi değiştirmedim. Eğer sorunu gözlemlemiyorsanız belki de kullandığım regex'in lezzeti. Ben regex101site kullanıyordum, bence php tarzı regex.
Crowcoder

İşte bahsettiğim şeyin demosu. Boylamla eşleşmesini bekliyordum (-96.74025) ama öyle değil.
Crowcoder

@Crowcoder Teşekkür ederim. Evet, bunun nedeni, bir çapa görevi gören ve çakışan eşleşmeleri önlemeye yardımcı olan, ancak girdinizle iyi oynamayan kelime sözcüğünden kaynaklanır. Ek bir grup, güncellenen cevapta belirtildiği gibi aslında daha iyi bir seçenektir.
wp78de

6

Bu versiyon

  • kaçan fiyat teklifleri
  • geri izlemeyi kontrol eder

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

Bu, birden fazla dizeyi kapsar ve çift ters eğik çizgiyi doğru bir şekilde ele almaz, örneğin dize: foo 'stri \\ 1' bar 'string 2' ve 'string 3' Debuggex Demo
miracle2k

Karakter sınıfında geri başvuru kullanamazsınız.
HamZa

5

DAHA CEVAPLAR! İşte kullandığım çözüm

\"([^\"]*?icon[^\"]*?)\"

TLDR;
kelime simgesi yerine tırnak ve voila içinde aradığınız ile değiştirin !


Bu şekilde çalışır, anahtar kelime arar ve tırnak işaretleri arasında başka bir şey umurumda değil. EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
normal ifade bir teklif işareti "
arar ve "
bulana kadar olası herhangi bir harf grubunu arar icon
ve olmayan herhangi bir olası harf grubunu "
arar."


1
Çok teşekkür ederim. her geçtiği yerini başardı name="value"ile name={"value"}bu cevabım regex getiriler beri icon/ value(kabul yanıt aksine) ikinci grup olarak. Bul : =\"([^\"]*?[^\"]*?)\" Değiştir :={"$1"}
Palisand

Aşağı oyu açıklamak ister misiniz? bazı durumlarda iyi çalışır.
James Harrington

Bana cevap veriyor musun?
Palisand

@ Palisand kimse bu gün hiçbir açıklama yapmadan bu yazıyı oy kullanmadı.
James Harrington

bu, tırnak içinde belirli bir metni bulan tek cevap gibi görünüyor
Top-Master

4

Axeman'ın daha geniş versiyonunu beğendim, ancak bununla ilgili bir sorun yaşadım (örneğin eşleşmedi)

foo "string \\ string" bar

veya

foo "string1"   bar   "string2"

doğru, bu yüzden düzeltmeye çalıştım:

# 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

3
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

sadece bunu deneyin, bir cazibe gibi çalışır !!!

\ atlama karakterini gösterir


Bu ilk satır gerçek Python kodu ise, dizeyi oluşturur " foo bar" "loloo". Ben size regex ile yaptığı gibi bir ham dizede o sarmak içindir şüpheli: r'"\" foo bar\" \"loloo\""'. Lütfen uygun olduğunda SO'nun mükemmel biçimlendirme özelliklerini kullanın . Sadece kozmetik değil; bunları kullanmazsanız ne söylemeye çalıştığınızı tam olarak söyleyemeyiz. Ve Stack Overflow'a hoş geldiniz !
Alan Moore

tavsiye alan için teşekkürler, aslında bu topluluk için yeniyim, bir dahaki sefere tüm bunları akılda tutacağım ... samimi özür dilerim.
mobman

2

Adam'ın cevabından farklı olarak, basit ama işe yarayan bir cevabım var:

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

Ve bunun gibi alıntılarla içerik almak istiyorsanız parantez ekleyin:

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

Sonra $1alıntı char ile $2eşleşir ve içerik dizesiyle eşleşir.


1
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'

Bunun sonucu:> Foo Bar <> <> ama bu <

Burada netlik için> <'s arasındaki sonuç dizesini gösterdim, ayrıca bu sed komutuyla açgözlü olmayan sürümü kullanarak önce ""' den önce ve sonra önemsizleri atıyoruz ve bunu "" arasındaki parçayla değiştiriyoruz. 've bunu> <' s ile çevreleyin.


1

Greg H.'den bu regex'i ihtiyaçlarımı karşılayabildim.

Tekliflerin içinde kalarak nitelendirilen belirli bir değeri eşleştirmem gerekiyordu. Tam bir eşleşme olmalı, hiçbir kısmi eşleşme isabeti tetikleyemez

örneğin "test", "test2" ile eşleşemedi.

reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
    print "winning..."

avcı


1

Nokta sözdizimi gibi yalnızca belirli bir son eki olan dizeleri bulmaya çalışıyorsanız, bunu deneyebilirsiniz:

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

Son .localizedek nerede ?

Misal:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

Yakalayacak "this is something I need to return".localizedve "so is this".localizedolmayacak "but this is not".


1

Microsoft VBA kodlayıcılarının alt kümesi için ek bir yanıt kitaplığı kullanır Microsoft VBScript Regular Expressions 5.5ve bu aşağıdaki kodu verir

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

0

Benim için bu çalıştı:

|([\'"])(.*?)\1|i

Bunun gibi bir cümlede kullandım:

preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);

ve harika çalıştı.


Bu yaklaşımın zayıflığı, bir dize tek bir alıntıyla başladığında ve çift tırnakla bittiğinde veya tam tersi olduğunda eşleşeceğidir.
Ghopper21

Ayrıca "@ unutma" yakalamak için sorunları var - "Don" sonra durur.
Benny Neugebauer

0

Yukarıdaki tüm cevaplar iyidir .... hariç tüm unicode karakterleri desteklemez! ECMA Script'te (Javascript)

Düğüm kullanıcısıysanız, kabul edilen yanıtın tüm unicode karakterleri destekleyen değiştirilmiş sürümünü isteyebilirsiniz:

/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu

Burada deneyin .


1
Unicode olmayan karakter nedir? AFAIK unicode tüm karakterleri kapsar .
Toto

1
Neden bir javascript sorusu olduğunu tahmin ediyorsunuz? Ayrıca, lookbehind tüm tarayıcılarda desteklenmez, regex101 atar? The preceding token is not quantifiable
Toto

@Toto, Demek istediğim "tüm unicode karakteri desteklemiyor". Teşekkür ederim. Soru genel olarak normal ifade ile ilgili olsa da, kelime sınır iddialarının kullanımının Javascript'te istenmeyen davranışlara neden olacağını vurgulamak istemiyorum. Ve elbette, Javascripts genellikle tarayıcı için olsa da, Düğüm de var.
Donovan P
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.