2010-01-21 11 views
10

So che è facile abbinare qualsiasi cosa eccetto un determinato carattere usando un'espressione regolare.Come posso abbinare le stringhe che non corrispondono ad un particolare modello in Perl?

$text = "ab ac ad"; 
$text =~ s/[^c]*//g; # Match anything, except c. 

$text is now "c". 

Non so come "tranne" stringhe anziché caratteri. Come potrei "abbinare qualsiasi cosa, eccetto" ac ""? Ho provato [^ (ac)] e [^ "ac"] senza successo.

È possibile a tutti?

+0

Per la semplice "stringa è (non) contenuta in un'altra stringa" è preferibile utilizzare l'indice (restituisce -1 se non è contenuto). Ho scritto un parser del file di log del server di posta uno che per primo utilizzava regexp per questi semplici controlli, dopo che sono passato a index() il tempo di esecuzione è stato ridotto a circa il 25% rispetto alla versione regexp. Come indice bonus() potrebbe essere più facile da leggere. – dbemerlin

+5

Qual è il tuo obiettivo finale esattamente? (1) corrisponde a una stringa che non contiene 'ac' (o qualche altra sottostringa), o (2) sostituisce tutto in una stringa tranne la sottostringa' ac' (ad esempio cambia 'abacadac' in' acac')? Sospetto che sia il secondo. –

+0

Per aggiungere al commento di @ Bart: Fornire esempi di: (1) stringa che si desidera convalidare e invalidare la stringa OR (2) da estrarre da questa stringa OPPURE (3) il risultato di sostituzioni in questa stringa. – Kobi

risposta

0

È possibile modificare facilmente questo regex per il vostro scopo.

use Test::More 0.88; 

#Match any whole text that does not contain a string 
my $re=qr/^(?:(?!ac).)*$/; 
my $str='ab ac ad'; 

ok(!$str=~$re); 

$str='ab af ad'; 
ok($str=~$re); 

done_testing(); 
+0

Mark Byers: con una semplice modifica, funzionerebbe su qualsiasi parte della stringa, è solo un esempio. –

+0

Ho cambiato idea: questo non funzionerà per la stessa ragione per cui le altre soluzioni che sono state pubblicate qui non funzioneranno: rimuoverà il c. Prova a fare la "modifica semplice" in un test completo e guarda cosa succede. –

+0

La domanda era: "corrisponde a qualsiasi cosa, eccetto" ac "". Con la rimozione di^$ nella mia regex, corrisponderebbe a qualsiasi cosa, fermandosi a "ac". –

1

è possibile utilizzare index()

$text = "ab ac ad"; 
print "ac not found" if (index($text,"ac") == -1); 
5

Di seguito risolve la questione come inteso nel secondo senso descritto nel Bart K. commento:

>> $text='ab ac ad'; 
>> $text =~ s/(ac)|./\1/g; 
>> print $text; 
ac 

Inoltre, 'abacadac' ->'acac'

Si noti tuttavia che nella maggior parte delle applicazioni pratiche le risposte negative appaiono più utili di questo approccio.

+1

Creativo! :) (minimo 15 caratteri) –

+0

Grazie :) (stesso limite qui) –

+0

Mi colpisca :-). Un leggero miglioramento potrebbe essere fare s/(\ bac \ b) /./ \ 1/g che significa 'ac fac ac' -> acac –

2

Se si desidera verificare se la stringa non contiene "ac", utilizzare solo una negazione.

$text = "ab ac ad"; 

print "ac not found" if $text !~ /ac/; 

o

print "ac not found" unless $text =~ /ac/; 
2
$text =~ s/[^c]*//g; // Match anything, except c. 

@ssn, Un paio di commenti sulla tua domanda:

  1. "//" non è un commento in Perl. Solo " ".
  2. "[^ c] *" - non è necessario per il "*" lì. "[^ c]" indica la classe di carattere composta da tutti i caratteri eccetto la lettera "c". Quindi si utilizza il modificatore/g, , nel senso che tutte le occorrenze di questo tipo nel testo saranno sostituite da (nell'esempio, con nulla ). Il modificatore "zero o più" ("*") è quindi ridondante.

Come dovrei "corrispondere nulla, se non 'ac'"? Ho provato [^ (ac)] e [^ "ac"] senza successo.

Si prega di leggere la documentazione su classi di caratteri (vedere "perldoc perlre" sulla linea di comando, oppure online all'indirizzo http://perldoc.perl.org/perlre.html) - vedrete si afferma che per l'elenco dei caratteri all'interno della piazza parentesi il RE " abbinare qualsiasi carattere dalla lista ". L'ordine di significato non è rilevante e non ci sono "stringhe", solo una lista di caratteri. "()" e le virgolette non hanno alcun significato speciale all'interno delle parentesi quadre.

Ora non sono esattamente sicuro del perché si parli di abbinamento, ma si faccia un esempio di sostituzione.Ma per vedere se una stringa non corrisponde al "ac" stringa è sufficiente per negare la partita:

use strict; use warnings; 
my $text = "ab ac ad"; 
if ($text !~ m/ac/) { 
    print "Yey the text doesn't match 'ac'!\n"; # this shouldn't be printed 
} 

Diciamo che avete uno stringa di testo all'interno del quale sono incorporate più occorrenze di una sottostringa. Se si desidera solo il testo che circonda il sub-string, basta rimuovere tutte le occorrenze della sub-string:

$text =~ s/ac//g; 

Se si vuole il contrario - per rimuovere tutto il testo ad eccezione di tutte le occorrenze della sub-string, I suggerirebbe qualcosa come:

use strict; use warnings; 
my $text = "ab ac ad ac ae"; 
my $sub_str = "ac"; 
my @captured = $text =~ m/($sub_str)/g; 
my $num = scalar @captured; 
print (($sub_str x $num) . "\n"); 

Questo conta sostanzialmente il numero di volte che il sub-string compare nel testo e stampa il sub-stringa che certo numero di volte con l'operatore "x". Non molto elegante, sono sicuro che un Perl-guru potrebbe inventarsi qualcosa di meglio.


@ennuikiller:

my $text = "ab ac ad"; 
$text !~ s/(ac)//g; # Match anything, except ac. 

Questo non è corretto, dal momento che genera un messaggio di avviso ("uso inutile del modello negativo vincolante (~) in un contesto vuoto!") Nel capitolo "Uso avvertimenti" e non fare altro che rimuovere tutte le stringhe "AC" dal testo, che potrebbe essere scritto più semplicemente come ho scritto sopra con:

$text =~ s/ac//g; 
2

Aggiornamento: In un commento sulla tua domanda, hai menzionato che vuoi pulire il markup wiki e rimuovere le sequenze bilanciate di {{ ... }}. Sezione 6 del Perl FAQ copre questo: Can I use Perl regular expressions to match balanced text?

Si consideri il seguente programma:

#! /usr/bin/perl 

use warnings; 
use strict; 

use Text::Balanced qw/ extract_tagged /; 

# for demo only 
*ARGV = *DATA; 

while (<>) { 
    if (s/^(.+?)(?=\{\{)//) { 
    print $1; 
    my(undef,$after) = extract_tagged $_, "{{" => "}}"; 

    if (defined $after) { 
     $_ = $after; 
     redo; 
    } 
    } 

    print; 
} 

__DATA__ 
Lorem ipsum dolor sit amet, consectetur 
adipiscing elit. {{delete me}} Sed quis 
nulla ut dolor {{me too}} fringilla 
mollis {{ quis {{ ac }} erat. 

La sua uscita:

Lorem ipsum dolor sit amet, consectetur 
adipiscing elit. Sed quis 
nulla ut dolor fringilla 
mollis {{ quis erat.

Per esempio particolare, è possibile utilizzare

$text =~ s/[^ac]|a(?!c)|(?<!a)c//g; 

Cioè, elimina solo un a o c quando non fanno parte di una sequenza ac.

In generale, questo è difficile da fare con un'espressione regolare.

Dire che non si desidera foo seguito da spazi bianchi facoltativi e quindi bar in $str. Spesso, è più chiaro e più facile da controllare separatamente. Per esempio:

die "invalid string ($str)" 
    if $str =~ /^.*foo\s*bar/; 

Potreste anche essere interessati a an answer to a similar question, dove ho scritto

my $nofoo = qr/ 
    (  [^f] | 
    f (?! o) | 
    fo (?! o \s* bar) 
)* 
/x; 

my $pattern = qr/^ $nofoo bar /x; 

Per capire la complicazione, leggo How Regexes Work da Mark Dominus. Il motore compila le espressioni regolari nelle macchine a stati. Quando è il momento di corrispondere, alimenta la stringa di input alla macchina di stato e controlla se la macchina di stato finisce in uno stato di accettazione.Quindi per escludere una stringa, devi specificare una macchina che accetta tutti gli input eccetto una particolare sequenza.

Ciò che può essere d'aiuto è un commutatore di espressioni regolari /v che crea la macchina a stati come al solito, ma poi integra il bit di stato di accettazione per tutti gli stati. È difficile dire se questo sarebbe davvero utile rispetto ai controlli separati perché un'espressione regolare /v può ancora sorprendere le persone, solo in modi diversi.

Se siete interessati ai dettagli teorici, vedere An Introduction to Formal Languages and Automata di Peter Linz.

Problemi correlati