2009-06-29 11 views
5

Sto provando a scrivere un'espressione regolare che corrisponda a tutto MA un apostrofo che non è stato sfuggito. Si consideri quanto segue:In che modo le espressioni regolari possono ignorare le virgolette con escape quando si confrontano le stringhe?

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

Il mio obiettivo è scrivere un'espressione regolare che essenzialmente corrisponde alla parte di stringa di quello. Sto pensando a qualcosa come

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

al fine di corrispondere una semplice stringa, ma ho cercato di capire come ottenere un lookbehind negativo lavorare su quel apostrofo per assicurarsi che non sia preceduta da un backslash ...

Qualche idea?

- JMT

risposta

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"; 
} 

stampe

<?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

Votare perché hai fornito casi di test. –

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

La quota tra parentesi cerca non apostrofi/backslash e caratteri backslash escape. Se solo alcuni caratteri possono essere sfuggiti cambia il \\. a \\['\\a-z], o qualsiasi altra cosa.

+0

quasi, ma questo non significa gestire il caso patologico ... 'La mia stringa termina con un backslash \\' –

+0

Grazie John! Fortunatamente per me, i casi che ho intenzione di trattare possono essere limitati e non arriveranno mai al problema descritto da the.jxc. Soluzione molto semplice, di cui avrei davvero dovuto pensare. Grazie ancora! :) – JMTyler

0

Via aspetto negativo dietro:

/ 
.*?'    #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

Ecco la mia soluzione con casi di test:

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

E la mia (Perl, ma io non usare tutte le funzioni Perl-speciali Io non credo) a prova:

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"; 
    } 
} 

L'esecuzione di questo mostra:

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

notare che il carattere jolly iniziale nel l'inizio deve essere non-goloso. Quindi utilizzo le corrispondenze non di backtracking per inghiottire \\ e \ 'e quindi qualsiasi altra cosa che non sia un carattere di citazione indipendente.

Penso che questo probabilmente imita l'approccio integrato del compilatore, che dovrebbe renderlo piuttosto a prova di proiettile.

0

questo è per JavaScript:

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

esso ...

    stringhe tra virgolette
  • partite singole o doppie
  • partite stringhe vuote (lunghezza 0)
  • partite stringhe con spazi bianchi incorporati (\n, \t, ecc.)
  • cassonetti interne escape virgolette (singole o doppie)
  • cassonetti apici tra virgolette e viceversa

Solo la prima citazione viene catturato. È possibile catturare la stringa non quotati in $ 2 con:

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

Problemi correlati