2012-03-15 7 views
13

Sto cercando di sfuggire a diversi caratteri speciali in una determinata stringa usando perl regex. Funziona bene per tutti i personaggi ad eccezione del simbolo del dollaro. Ho provato quanto segue:

my %special_characters; 
$special_characters{"_"} = "\\_"; 
$special_characters{"$"} = "\\$"; 
$special_characters{"{"} = "\\{"; 
$special_characters{"}"} = "\\}"; 
$special_characters{"#"} = "\\#"; 
$special_characters{"%"} = "\\%"; 
$special_characters{"&"} = "\\&"; 

my $string = '$foobar'; 
foreach my $char (keys %special_characters) { 
    $string =~ s/$char/$special_characters{$char}/g; 
} 
print $string; 

risposta

17

Prova questa:

my %special_characters; 
$special_characters{"_"} = "\\_"; 
$special_characters{"\\\$"} = "\\\$"; 
$special_characters{"{"} = "\\{"; 
$special_characters{"}"} = "\\}"; 
$special_characters{"#"} = "\\#"; 
$special_characters{"%"} = "\\%"; 
$special_characters{"&"} = "\\&"; 

sembra strano, giusto? Il tuo regex ha bisogno di guardare come segue:

s/\$/\$/g 

Nella prima parte della regex, "$" deve essere sfuggito, perché è un carattere speciale regex che indica la fine della stringa.

La seconda parte della regex è considerata una stringa "normale", dove "$" non ha un significato speciale. Quindi il backslash è un vero backslash, mentre nella prima parte viene utilizzato per sfuggire al segno del dollaro.

Inoltre nella definizione della variabile è necessario sfuggire al backslash e al simbolo del dollaro, poiché entrambi hanno un significato speciale nelle stringhe con virgolette doppie.

+2

Migliore approccio: usa 'quotemeta()' o 's/\ Q $ char \ E/...' Ricordati di farlo per ogni variabile $, poiché le regex vengono interpolate. – hhaamu

0

$ ha un significato speciale in regexp, vale a dire "fine della stringa". Si sarebbe meglio con qualcosa di simile:

# escape special characters, join them into a single line 
my $chars = join '', map { "\\$_" } keys %special_characters; 
$string =~ s/([$chars])/$special_characters{$1}/g; 

Inoltre, Perl non piace molto "$", un uso migliore '$' (apici => senza interpolazione).

UPDATE: Siamo spiacenti, stavo scrivendo questo in fretta => troppe modifiche :(

+0

Grazie per il tuo feedback, la tua soluzione sembra davvero fantastica! Comunque sono obbligato ad usare il codice più semplice (lavoro di squadra) ... Grazie per l'heads up delle virgolette singole –

1

Non è necessario un hash se si sta sostituendo ogni carattere con se stessa preceduto da un backslash Just. corrispondere a quello che ti serve e mettere un backslash davanti ad esso:.

s/($re)/"\\$1"/eg; 

per costruire l'espressione regolare per tutti i personaggi, Regexp::Assemble è veramente bello

use v5.10.1; 
use Regexp::Assemble; 

my $ra = Regexp::Assemble->new; 

my @specials = qw(_ $ { } # % &); 

foreach my $char (@specials) { 
    $ra->add("\\Q$char\\E"); 
    } 

my $re = $ra->re; 
say "Regex is $re"; 

while(<DATA>) { 
    s/($re)/"\\$1"/eg; 
    print; 
    } 

__DATA__ 
There are $100 dollars 
Part #1234 
Outside { inside } Outside 

Nota come, nella prima riga di input, Regexp :: Assemble ha riorganizzato il mio pattern. Non è solo il incollati insieme bit delle parti che ho aggiunto:

Regex is (?^:(?:[#$%&_]|\{|\})) 
There are \$100 dollars 
Part \#1234 
Outside \{ inside \} Outside 

Se si desidera aggiungere più personaggi, basta mettere il personaggio in @specials. Tutto il resto accade per te.

Problemi correlati