2015-09-21 22 views
7

voglio dividere una stringa utilizzando le lettere che si ripetono come delimitatore, ad esempio, "123aaaa23a3" dovrebbe essere diviso come ('123', '23a3') mentre "123abc4" dovrebbe essere lasciato invariato.
Così ho provato questo:Perl funzione Split - uso ripetendo caratteri come delimitatore

@s = split /([[:alpha:]])\1+/, '123aaaa23a3'; 

Ma questo restituisce '123', 'a', '23a3', che non è quello che volevo. Ora so che questo è dovuto al fatto che l'ultimo 'a' in 'aaaa' viene catturato dalle parentesi e quindi conservato da split(). Ma comunque, non posso aggiungere qualcosa come ?: dal momento che [[:alpha:]] deve essere catturato per riferimento posteriore. Come posso risolvere questa situazione?

+1

Non penso che sia possibile modificare la regex per evitare di avere un gruppo di cattura, ma * puoi * semplicemente buttare via tutti gli elementi dispari della lista restituita da 'split' – hobbs

+2

Se l'espressione regolare ha gruppi di cattura , l'elenco restituito contiene anche le sottostringhe corrispondenti/raggruppate. Potresti usare un'alternativa: 'my $ str = '123aaaa23a3' = ~ s/([[: alpha:]]) \ 1 +/~~/r; my @s = split/~~ /, $ str; ' – hwnd

risposta

4

Hmm, è interessante. Il mio primo pensiero sarebbe: il tuo delimitatore sarà sempre un numero dispari, quindi puoi semplicemente scartare tutti gli elementi di un numero dispari.

Qualcosa di simile forse ?:

my %s = (split (/([[:alpha:]])\1+/, '123aaaa23a3'), ''); 
print Dumper \%s; 

Questo ti darà:

$VAR1 = { 
      '23a3' => '', 
      '123' => 'a' 
     }; 

in modo da poter estrarre il vostro modello tramite keys.

Sfortunatamente il mio secondo approccio di "selezione" del pattern corrisponde a %+ non aiuta in modo particolare (split non popola le cose di tipo regex).

Ma qualcosa di simile:

my @delims ='123aaaa23a3' =~ m/(?<delim>[[:alpha:]])\g{delim}+/g; 
print Dumper \%+; 

Utilizzando una cattura di nome, identifichiamo che a da gruppo di cattura. Sfortunatamente, questo non sembra essere popolato quando lo fai tramite split - che potrebbe portare a un approccio a due passaggi.

Questo è il più vicino ho ottenuto:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use Data::Dumper; 

my $str = '123aaaa23a3'; 

#build a regex out of '2-or-more' characters. 
my $regex = join ("|", map { $_."{2,}"} $str =~ m/([[:alpha:]])\1+/g); 
#make the regex non-capturing 
$regex = qr/(?:$regex)/; 
print "Using: $regex\n"; 

#split on the regex 
my @s = split m/$regex/, $str; 

print Dumper \@s; 

Abbiamo primo processo la stringa per estrarre "2-o-più" modelli di caratteri, per impostare come i nostri delmiters. Quindi assembliamo una regex, usando non-capturing, così possiamo dividere.

+0

Grazie! Questa è una soluzione semplice. – AaronS

2

Una soluzione sarebbe utilizzare la chiamata originale split e buttare via ogni altro valore. Comodamente, List::Util::pairkeys è una funzione che mantiene il primo di ogni coppia di valori nella sua lista di input:

use List::Util 1.29 qw(pairkeys); 

my @vals = pairkeys split /([[:alpha:]])\1+/, '123aaaa23a3'; 

Odd number of elements in pairkeys at (eval 6) line 1. 
[ '123', '23a3' ] 

Questo allarme arriva dal fatto che pairkeys vuole una lista, anche di dimensioni.Possiamo risolvere che aggiungendo un valore più alla fine:

my @vals = pairkeys split(/([[:alpha:]])\1+/, '123aaaa23a3'), undef; 

In alternativa, e forse un po 'più ordinato, è quello di aggiungere quel valore in più all'inizio della lista e utilizzare pairvalues invece:

use List::Util 1.29 qw(pairvalues); 

my @vals = pairvalues undef, split /([[:alpha:]])\1+/, '123aaaa23a3'; 
0

il 'raggruppati' può essere fatto funzionare direttamente utilizzando l'asserzione ritardata esecuzione (alias rinviata subexpression regolare), (??{ code }), nell'espressione regolare:

@s = split /[[:alpha:]](??{"$&+"})/, '123aaaa23a3'; 

(??{ code }) è documentato sulla pagina di manuale 'perlre'.

Si noti che, in base alla pagina di manuale 'perlvar', l'uso di $& in qualsiasi punto di un programma impone una notevole riduzione delle prestazioni su tutte le corrispondenze di espressioni regolari. Non ho mai trovato questo problema, ma YMMV.

Problemi correlati