2012-12-03 10 views
7

Questa domanda è ispirata a this other one.Perché il lookahead (a volte) è più veloce della cattura?

Confrontando s/,(\d)/$1/-s/,(?=\d)//: il primo utilizza un gruppo di cattura per sostituire solo la cifra, ma non la virgola, quest'ultimo utilizza un lookahead per determinare se la virgola è sostituito da una cifra. Perché quest'ultimo è talvolta più veloce, come discusso in this answer?

+1

facendo alcuni test di benchmark sui due regex non può davvero determinare ogni grande differenza. Entrambi sono molto veloci. Nota che ciò si applica a queste regex, non a catturare vs lookahead. – TLP

+4

È ovvio: acquisire forza di gruppo per copiare i dati e poi sostituirli richiede l'interpolazione di '$ 1', mentre la seconda regex è solo trovare/controllare/rimuovere. Tuttavia, la differenza di velocità dovrebbe essere invisibile. – PSIAlt

risposta

4

I due approcci fanno cose diverse e hanno diversi tipi di costi generali. Quando lo catturi, perl deve fare una copia del testo catturato. Partite look-ahead senza consumo; deve segnare la posizione in cui inizia. Si può vedere cosa succede usando il re 'debug' pragma:

use re 'debug'; 
my $capture = qr/,(\d)/; 
 
Compiling REx ",(\d)" 
Final program: 
    1: EXACT (3) 
    3: OPEN1 (5) 
    5: DIGIT (6) 
    6: CLOSE1 (8) 
    8: END (0) 
anchored "," at 0 (checking anchored) minlen 2 
Freeing REx: ",(\d)" 
use re 'debug'; 
my $lookahead = qr/,(?=\d)/; 
 
Compiling REx ",(?=\d)" 
Final program: 
    1: EXACT (3) 
    3: IFMATCH[0] (8) 
    5: DIGIT (6) 
    6: SUCCEED (0) 
    7: TAIL (8) 
    8: END (0) 
anchored "," at 0 (checking anchored) minlen 1 
Freeing REx: ",(?=\d)" 

mi aspetto look-ahead per essere più veloce di catturare nella maggior parte dei casi, ma come notato in altro thread le prestazioni regex possono dipendere dai dati.

+0

Avrei dovuto pensare al 're' pragma. Grazie! – mpe

-1

Come sempre, quando si vuole sapere quale dei due pezzi di codice funziona più velocemente, è necessario testarlo:

#!/usr/bin/perl 

use 5.012; 
use warnings; 
use Benchmark qw<cmpthese>; 

say "Extreme ,,,:"; 
my $Text = ',' x (my $LEN = 512); 
cmpthese my $TIME = -10, my $CMP = { 
    capture => \&capture, 
    lookahead => \&lookahead, 
}; 

say "\nExtreme ,0,0,0:"; 
$Text = ',0' x $LEN; 
cmpthese $TIME, $CMP; 

my $P = 0.01; 
say "\nMixed (@{[$P * 100]}% zeros):"; 
my $zeros = $LEN * $P; 
$Text = ',' x ($LEN - $zeros) . ',0' x $zeros; 
cmpthese $TIME, $CMP; 

sub capture { 
    local $_ = $Text; 
    s/,(\d)/$1/; 
} 

sub lookahead { 
    local $_ = $Text; 
    s/,(?=\d)//; 
} 

Il benchmark test tre casi diversi:

  1. Solo', '
  2. Solo', 0'
  3. 1% '0' , resto','

Sulla mia macchina e con la mia versione Perl, produce questi risultati:

Extreme ,,,: 
      Rate capture lookahead 
capture 23157/s  --  -1% 
lookahead 23362/s  1%  -- 

Extreme ,0,0,0: 
       Rate capture lookahead 
capture 419476/s  --  -65% 
lookahead 1200465/s  186%  -- 

Mixed (1% zeros): 
      Rate capture lookahead 
capture 22013/s  --  -4% 
lookahead 22919/s  4%  -- 

Questi risultati comprovino l'ipotesi che la versione look-ahead è significativamente più veloce rispetto alla cattura, salvo il caso di quasi solo virgole. Ed è davvero poco sorprendente come già spiegato da PSIAlt nel suo commento.

saluti, Matthias

+1

La domanda non è _che_ è più veloce, ma _why_. –

+0

So come testarlo e in effetti, l'ho fatto anch'io. Grazie per aver dimostrato, però; i tuoi risultati sono molto illustrativi! – mpe

Problemi correlati