2009-06-29 13 views
5

Próbuję napisać wyrażenie regularne, które będzie pasować do wszystkiego, ale apostrofu, który nie został zmieniony. Rozważ następujące:W jaki sposób można wyrejestrować zignorowane cudzysłowy przy dopasowywaniu ciągów?

<?php $s = 'Hi everyone, we\'re ready now.'; ?> 

Moim celem jest napisanie wyrażenia regularnego, które zasadniczo będzie pasowało do części łańcuchowej tego. Myślę o czymś takim jak

/.*'([^']).*/ 

w celu dopasowania prosty ciąg znaków, ale już próbuje dowiedzieć się, jak dostać negatywny lookbehind pracuje nad tym apostrofu aby zapewnić, że nie jest poprzedzone backslash ...

Jakieś pomysły?

- JMT

Odpowiedz

3
<?php 
$backslash = '\\'; 

$pattern = <<< PATTERN 
#(["'])(?:{$backslash}{$backslash}?+.)*?{$backslash}1# 
PATTERN; 

foreach(array(
    "<?php \$s = 'Hi everyone, we\\'re ready now.'; ?>", 
    '<?php $s = "Hi everyone, we\\"re ready now."; ?>', 
    "xyz'a\\'bc\\d'123", 
    "x = 'My string ends with with a backslash\\\\';" 
    ) as $subject) { 
     preg_match($pattern, $subject, $matches); 
     echo $subject , ' => ', $matches[0], "\n\n"; 
} 

drukuje

<?php $s = 'Hi everyone, we\'re ready now.'; ?> => 'Hi everyone, we\'re ready now.' 

<?php $s = "Hi everyone, we\"re ready now."; ?> => "Hi everyone, we\"re ready now." 

xyz'a\'bc\d'123 => 'a\'bc\d' 

x = 'My string ends with with a backslash\\'; => 'My string ends with with a backslash\\' 
+0

Głosowanie, ponieważ dostarczyłeś przypadki testowe. –

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

Część nawiasach szuka non-apostrof/ukośniki i znaki backslash-uciekł. Jeśli tylko niektóre znaki mogą zostać zmienione, zmień wartość \\. na lub coś podobnego.

+0

Bardzo prawie, ale nie radzi sobie patologiczny przypadek ... „Mój ciąg kończy się z backslashem \\” –

+0

Dzieki John! Na szczęście dla mnie przypadki, z którymi będę musiał się uporać, mogą być powściągliwe i nigdy nie osiągną problemu opisanego przez the.jxc. Bardzo proste rozwiązanie, o którym naprawdę powinienem pomyśleć. Jeszcze raz, dziękuję! :) – JMTyler

0

Via negatywnym spojrzeniem za:

/ 
.*?'    #Match until ' 
(
.*?    #Lazy match & capture of everything after the first apostrophe 
)  
(?<!(?<!\\)\\)' #Match first apostrophe that isn't preceded by \, but accept \\ 
.*    #Match remaining text 
/
0
Regex reg = new Regex("(?<!\\\\)'(?<string>.*?)(?<!\\\\)'"); 
3

Oto moje rozwiązanie z przypadków testowych:

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

A moja (Perl, ale nie wszystkie funkcje Perl specyficzne nie sądzę) dowód:

use strict; 
use warnings; 

my %tests =(); 
$tests{'Case 1'} = <<'EOF'; 
$var = 'My string'; 
EOF 

$tests{'Case 2'} = <<'EOF'; 
$var = 'My string has it\'s challenges'; 
EOF 

$tests{'Case 3'} = <<'EOF'; 
$var = 'My string ends with a backslash\\'; 
EOF 

foreach my $key (sort (keys %tests)) { 
    print "$key...\n"; 
    if ($tests{$key} =~ m/.*?'((?:\\\\|\\'|[^'])*+)'/) { 
     print " ... '$1'\n"; 
    } else { 
     print " ... NO MATCH\n"; 
    } 
} 

Running to pokazuje:

$ perl a.pl 
Case 1... 
... 'My string' 
Case 2... 
... 'My string has it\'s challenges' 
Case 3... 
... 'My string ends with a backslash\\' 

pamiętać, że początkowy wieloznaczny u start musi być nie chciwy. Następnie używam dopasowań bez powrotu do tyłu, aby pożreć \\ i \ ', a następnie cokolwiek innego, co nie jest samodzielnym cudzysłowem.

Myślę, że ten prawdopodobnie naśladuje wbudowane podejście kompilatora, które powinno sprawić, że będzie on kuloodporny.

0

To dla JavaScriptu:

/('|")(?:\\\\|\\\1|[\s\S])*?\1/

go ...

  • mecze pojedyncze lub podwójne notowane ciągi
  • tenis pustych strun (długość 0)
  • tenis smyczki z osadzone białe znaki (\n, \t itp.)
  • przeskakuje wewnętrzne uciekł cytaty (pojedyncze lub podwójne)
  • przeskakuje apostrofów wewnątrz cudzysłowów i vice versa

Tylko pierwszy cytat jest opanowana. Można uchwycić niecytowany ciąg w $ 2, z:

/('|")((?:\\\\|\\\1|[\s\S])*?)\1/

Powiązane problemy