Kaçan tırnak işaretleriyle tırnak içine alınmış dize için normal ifade


122

" It's big \"problem "Normal ifade kullanarak alt dizeyi nasıl elde ederim ?

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

1
Yalnızca "Is" içeren bir dizede "O" nu nasıl bulursunuz? Bunu sizin için düzeltirdim, ancak kullandığınız dilde hangi tek alıntı / kaçış kurallarının geçerli olduğunu bilmiyorum.
Jonathan Leffler


2
Aslında tarihlere baktığımda, diğer sorunun bunun bir kopyası olduğunu görüyorum. Her iki durumda da cevabımı kontrol ettiğinizden emin olun .
ridgerunner

@ridgerunner: Önerdiğiniz gibi bunu kapatmak için oy veriyorum. Diğer sorunun daha yeni olduğu doğru, ama aynı zamanda çok daha iyi (çoğunlukla cevabınız sayesinde)
Alan Moore

Yanıtlar:


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

The Regex Coach ve PCRE Workbench'te çalışır.

JavaScript'te test örneği:

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


24
Mantıklı. Düz ingilizce: Sıfır veya daha fazla "tırnak veya ters eğik çizgi olmayan herhangi bir karakter" veya "ters eğik çizgi ve ardından herhangi bir karakter" i çevreleyen iki tırnak. Ben ... bunu düşünmüyordu inanamıyorum
Ajedi32

7
Kendim cevaplayacağım =) (?:...)pasif veya yakalamayan bir gruptur. Daha sonra geri referans alınamayacağı anlamına gelir.
magras

çok araştırma yaptıktan ve çok test ettikten sonra, bu yaygın soruna bulduğum gerçek ve tek çözüm bu. Teşekkürler!
kanserbero

10
Bunun için teşekkürler. tek alıntıları da eşleştirmek istedim, bu yüzden bunu buna uyarladım:/(["'])(?:[^\1\\]|\\.)*?\1/
leo

İle var s = ' my \\"new\\" string and \"this should be matched\"';, bu yaklaşım beklenmedik sonuçlara yol açacaktır.
Wiktor Stribiżew

32

Bu, birçok linux dağıtımında bulunan nanorc.sample'den geliyor. C tarzı dizelerin sözdizimi vurgulaması için kullanılır

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

İle var s = ' my \\"new\\" string and \"this should be matched\"';, bu yaklaşım beklenmedik sonuçlara yol açacaktır.
Wiktor Stribiżew

1
c.nanorc gittiğim ilk yerdi. Bunun gibi her şeyden çift çıkış yapana kadar bir C stringinin bir parçası olarak çalışması mümkün değildi" \"(\\\\.|[^\\\"])*\" "
hellork

Bu, libc'nin egrep ve re_comp / re_exec işlevleriyle çalışır.
fk0

19

EPharaoh tarafından sağlandığı gibi, cevap

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

Yukarıdakilerin tek tırnaklı veya çift tırnaklı dizelere uygulanmasını sağlamak için kullanın

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

2
Bu, 99 kaçış içeren tek, büyük bir 1,5 KB alıntı dizesiyle benim için çalışan tek küme. Bu sayfadaki diğer tüm ifadeler, metin düzenleyicimde bir taşma hatasıyla bozuldu. Buradaki çoğu tarayıcıda çalışsa da, akılda tutulması gereken bir şey. Fiddle: jsfiddle.net/aow20y0L
Beejor

3
Açıklama için @ MarcAndrePoulin'in aşağıdaki cevabına bakın.
shaunc

10

Burada sağlanan çözümlerin çoğu alternatif tekrar yollarını kullanır, yani (A | B) *.

Bazı desen derleyicileri bunu özyineleme kullanarak gerçekleştirdiğinden, büyük girdilerde yığın taşmalarıyla karşılaşabilirsiniz.

Örneğin Java: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993

Bunun gibi bir şey: "(?:[^"\\]*(?:\\.)?)*"veya Guy Bedford tarafından sağlanan, yığın taşmalarının çoğunu önleyerek ayrıştırma adımlarının miktarını azaltacaktır.



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

man perlrePerl 5.22.0 kurulu bir Linux sisteminden doğrudan alınmıştır . Bir optimizasyon olarak, bu normal ifade, her ikisinin de 'pozitif' biçimini kullanır +ve *geriye doğru izlemeyi önlemek için önceden bilinir, çünkü kapanış tırnağı olmayan bir dizenin hiçbir durumda eşleşmeyeceği önceden bilinmektedir.


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

alıntılanmış herhangi bir dizeyle çalışmalıdır


1
Güzel, ancak istek için fazla esnek (tek alıntılarla eşleşecek ...). Ve bir şeyi kaçırmazsam /".*?(?<!\)"/ olarak basitleştirilebilir. Oh, ve bazı diller (örn. JavaScript) ne yazık ki olumsuz geriye dönük ifadeleri anlamıyor.
PhiLho

1
@PhiLho, yalnızca tek bir (? <! \\) kullanmak, dizenin sonundaki öncelenmiş ters eğik çizgilerde başarısız olur. Yine de JavaScript'teki arkaya bakma hakkında doğru.
Markus Jarderot

4

Bu, PCRE'de mükemmel çalışır ve StackOverflow'a düşmez.

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

Açıklama:

  1. Alıntılanan her dizge Char ile başlar ":;
  2. Herhangi bir sayıda karakter içerebilir: .*?{Geç eşleşme}; kaçış olmayan karakterle biten [^\\];
  3. İfade (2) Lazy (!) İsteğe bağlıdır çünkü dize boş olabilir (""). Yani:(.*?[^\\])??
  4. Son olarak, alıntılanan her dizge Char ( ") ile biter , ancak önünde çift sayıda kaçış işareti çifti bulunabilir (\\\\)+; ve Açgözlü (!) isteğe bağlıdır: ((\\\\)+)?+{Açgözlü eşleştirme}, temelde dizge boş olabilir veya çift bitmeyen olabilir!

Bu, dünyanın en verimli modeli değil, ancak fikir ilginç. Bunu şu şekilde kısaltabileceğinizi unutmayın:"(.*?[^\\])?(\\\\)*"
Casimir et Hippolyte

2

burada hem "hem de" ile çalışan bir tane var ve başlangıçta başkalarını kolayca ekleyebilirsiniz.

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

geri referans (\ 1), birinci grupta ("veya ') olanla tam olarak eşleşir.

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


bu çok iyi bir çözümdür, ancak [^\1]bunun yerine geçmelidir .çünkü geriye dönük referans diye bir şey yoktur ve hiçbir şekilde önemi yoktur. ilk koşul, kötü bir şey olmadan önce daima eşleşecektir.
Seph Reed

@SephReed - değiştirirken [^\1]ile .etkili bir şekilde bu regex değiştirecek ("|').*?\1ve o zaman eşleşir "foo\"içinde "foo \" bar". Bununla birlikte, [^\1]gerçekten işe başlamak zor. @ Mathiashansen - Kullanışsız ve pahalı olanlarda daha iyi durumdasınız(?!\1). (bu nedenle, bir miktar verimlilik temizliği ile tüm normal ifadeler olabilir (["'])(?:\\.|(?!\1).)*+\1. +Motorunuz desteklemiyorsa isteğe bağlıdır.
Adam Katz

2

Daha önce değinilmeyen bir seçenek:

  1. Dizeyi ters çevirin.
  2. Ters dizide eşleştirmeyi gerçekleştirin.
  3. Eşleşen dizeleri yeniden ters çevirin.

Bu, kaçan açık etiketleri doğru şekilde eşleştirebilme avantajına sahiptir.

Aşağıdaki dizeye sahip olduğunuzu varsayalım; String \"this "should" NOT match\" and "this \"should\" match" Burada \"this "should" NOT match\"eşleştirilmemeli ve "should"olmalıdır. Bunun üzerine this \"should\" matchuyumlu ve gerektiği \"should\"olmamalı.

Önce bir örnek.

// 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"']

Tamam, şimdi RegExp'i açıklayalım. Bu regexp kolayca üç parçaya bölünebilir. Aşağıdaki gibi:

# 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
)

Bu muhtemelen resim biçiminde çok daha nettir: Jex'in Regulex'i kullanılarak oluşturulmuştur

Github üzerindeki resim (JavaScript Normal İfade Görselleştirici.) Üzgünüm, resimleri eklemek için yeterince yüksek itibarım yok, bu yüzden şimdilik sadece bir bağlantı.

İşte biraz daha gelişmiş olan bu kavramı kullanan örnek bir fonksiyonun özü: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js


0

Normal ifadelerin string-y olan her şey için sihirli ifadeler olmadığını hatırlamak gerekir. Bazı şeyler bir imleç ve doğrusal, manuel arama ile yapmak daha kolaydır. Bir CFL bu işi oldukça önemsiz bir şekilde yapar, ancak çok fazla CFL uygulaması yoktur (afaik).


3
Yeterince doğru, ancak bu sorun normal ifadelerin yetenekleri dahilinde ve bunların pek çok uygulaması var.
Alan Moore


0

Etrafında haberci regexpal ve bu regex ile sona erdi: (nasıl çalıştığını Do yazdım bile tho zar zor lol anlamak bana sormayın)

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


0

Bazı dosyaların ayrıştırılmasına engel olabilecek alıntılanmış dizeleri kaldırmaya çalışırken benzer bir sorunla karşılaştım.

Bulabileceğiniz tüm kıvrımlı normal ifadeleri yenen iki adımlı bir çözüm buldum:

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

Okuması daha kolay ve muhtemelen daha verimli.


0

IDE'niz IntelliJ Idea ise, tüm bu baş ağrılarını unutabilir ve normal ifadenizi bir String değişkeninde saklayabilirsiniz ve çift tırnak içine kopyalayıp yapıştırdığınızda otomatik olarak normal ifadeyi kabul edilebilir bir biçime dönüşür.

Java'da örnek:

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

artık bu değişkeni regexp'inizde veya herhangi bir yerde kullanabilirsiniz.

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.