2013-09-30 8 views
6

qualcuno può spiegare questo strano comportamento:perl divisi comportamento interessante

ho percorso Hava in una stringa e voglio dividerlo per ogni backslash

my $path = "D:\Folder\AnotherFolder\file.txt"; 

my @folders = split('\', $path); 

nel caso di cui sopra non non funzionerà anche se fuggire il backslash come questo:

my @folders = split('\\', $path); 

ma nel caso di una regexp che funzionerà:

my @folders = split(/\\/, $path); 

perché è così?

+2

Le tue fughe nel percorso sono sbagliate. In una stringa doppia citazione, '\ Folder' è interpretato come una sequenza di escape' \ F'. – TLP

+4

È spiacevole usare le virgolette attorno al pattern di separazione per 'split' in quanto non esprime correttamente la semantica e causa una doppia compilazione. Usa sempre le barre, a meno che tu non voglia passare una stringa a spazio singolo per invocare il comportamento predefinito, quando '''' è la scelta corretta. – Borodin

+0

@TLP sì lo so, di solito metto solo virgolette singole per il percorso. grazie –

risposta

2

Se si guarda la documentazione eseguendo:

perldoc -f split 

vedrete tre forme di argomenti che split può prendere:

split /PATTERN/,EXPR,LIMIT 
split /PATTERN/,EXPR 
split /PATTERN/ 

Questo significa che anche quando si passa split una stringa come il primo argomento, perl, lo sta costringendo a un'espressione regolare.

Se guardiamo gli avvertimenti che otteniamo quando si cerca di fare qualcosa di simile in re.pl:

$ my $string_with_backslashes = "Hello\\there\\friend"; 
Hello\there\friend 
$ my @arry = split('\\', $string_with_backslashes); 
Compile error: Trailing \ in regex m/\/ at (eval 287) line 6. 

vediamo che prima, '\\' viene interpolata come un backslash escape seguito da una barra rovesciata reale, che restituisce un singolo backslash.

split poi mette il backslash abbiamo dato, e costringe a una regex come se avessimo scritto:

$ my @arry = split(/\/, $string_with_backslashes); 

che non funziona perché c'è solo una singola barra rovesciata che viene interpretato come semplicemente fuga la barra diretta dopo (senza avere una terminazione /) per mostrare che la regex è terminata.

+0

In realtà, se si stesse sfuggendo alla barra, si otterrebbe l'errore 'Cerca pattern non terminato', ovvero l'operatore era rotto . Questo è qualcos'altro. – TLP

+3

più esplicitamente: stringhe e regex hanno regole diverse per l'escape. Se una stringa viene utilizzata al posto di un'espressione regolare, i valori letterali stringa soffrono di doppia escape. – amon

+0

@ user1436026 Ho letto il perldoc, ma non ho capito bene il innerworks, non sapevo che qualunque cosa tu abbia inserito in '' viene ancora convertito e regexp –

5

penso amon dato la migliore risposta alla tua domanda letterale nel suo commento:

più esplicitamente: stringhe e regex hanno regole diverse per fuggire. Se una stringa viene usato al posto di una regex, le stringhe letterali soggetti ad una doppia fuga

Significato che split '\\' utilizza una stringa e split /\\/ usa un'espressione regolare.

Come risposta pratica, ho voluto aggiungere questo:

forse si dovrebbe considerare l'utilizzo di un modulo adatto per i percorsi di scissione. File::Spec è un modulo principale in Perl 5. E inoltre, devi eseguire il backslash di escape in una stringa doppia citata, cosa che non hai fatto. Puoi anche usare le virgolette singole, che a mio parere sono un po 'migliori.

use strict; 
use warnings; 
use Data::Dumper; 
use File::Spec; 

my $path = 'D:\Folder\AnotherFolder\file.txt'; # note the single quotes 
my @elements = File::Spec->splitdir($path); 
print Dumper \@elements; 

uscita:

$VAR1 = [ 
      'D:', 
      'Folder', 
      'AnotherFolder', 
      'file.txt' 
     ]; 
+0

grazie per il suggerimento con File :: Spec –

+0

@AndreiDoanca È lo strumento giusto per dividere i percorsi, ed è portatile e affidabile. Non sono sicuro di cosa stai cercando di fare dividendo il percorso, ma sembra un problema XY. – TLP

+0

in realtà non è un problema XY, solo una mia curiosità :) –

2

Uno dei modi più ordinato per estrarre gli elementi di un percorso è quello di estrarre tutte le sequenze di caratteri diversi un separatore di percorso.

use strict; 
use warnings; 

my $path = 'D:\Folder\AnotherFolder\file.txt'; 
my @path = $path =~ m([^/\\]+)g; 

print "$_\n" for @path; 

uscita

D: 
Folder 
AnotherFolder 
file.txt 
2

Quando split è utilizzato sotto forma di split STRING e non split REGEX, la stringa viene convertito in un regex. Nel tuo caso lo split '\\' verrà convertito in split /\/ poiché la prima barra retroversa è considerata un carattere di escape.

Il modo corretto per farlo è split '\\\\' che verrà tradotto in split /\\/.

+0

grazie mille per la spiegazione, informazioni davvero buone :) Capisco ora e vedo che funziona :) –