2010-03-24 15 views

risposta

10

Questo funziona:

$str =~ s/\b((\w+)\s+\2)\b/[\1]/g; 
+7

'$ str = ~ s/\ b (? (\ W +) (: \ s + \ 2) +) \ b/[\ 1]/g;' a corrisponde a un numero qualsiasi di ripetizioni –

+6

@briandfoy: ... che è esattamente ciò che la domanda ha richiesto, prima di modificarlo. E Eric ha postato in un commento una versione che corrisponde a più di una ripetizione. – Kip

+0

@brian: Come lo sai dalle 2 righe di contesto nella domanda originale? –

2

Si può provare:

$str = "Thus joyful Troy Troy maintained the the watch of night..."; 
$str =~s{\b(\w+)\s+\1\b}{[$1 $1]}g; 
print "$str"; # prints Thus joyful [Troy Troy] maintained [the the] watch of night... 

Regex utilizzato: \b(\w+)\s+\1\b

Spiegazione:

  • \b: parola bondary
  • \w+: una parola
  • (): per ricordare la parola sopra
  • \s+: spazi
  • \1 : il ricordo ered parola

Essa trova effettivamente due completi parole separate da spazi e pone [ ] li circonda.

EDIT:

Se si desidera conservare la quantità di spazio bianco tra le parole si possono usare:

$str =~s{\b(\w+)(\s+)\1\b}{[$1$2$1]}g; 
+0

questo non preserva la quantità e il tipo di spazi bianchi tra le parole duplicate, se questo è importante per OP – Kip

+0

@Kip: hai ragione. Grazie. Ho modificato i miei ans. – codaddict

+0

Questo trova solo due parole ripetute. Sarebbe meglio se trovasse tutte le parole ripetute. :) –

12

Questo è simile a una delle Learning Perl esercizi. Il trucco è quello di catturare tutte le parole ripetute, quindi è necessario un "uno o più" quantificatore sulla duplicazione:

$str = 'This is Goethe the the the their sentence'; 

$str =~ s/\b((\w+)(?:\s+\2\b)+)/[\1]/g; 

Le caratteristiche che sto per usare sono descritti in entrambi i perlre, quando si applicano a un modello o perlop quando influiscono sul modo in cui l'operatore di sostituzione esegue il proprio lavoro.

Se ti piace la bandiera /x per aggiungere spazi e commenti insignificante:

$str =~ s/ 
     \b 
     (
     (\w+) 
     (?: 
      \s+ 
      \2 
      \b 
     )+ 
    ) 
    /[\1]/xg; 

non mi piace che \2, però, perché io odio il conteggio posizioni relative. Posso usare le relative backreferences in Perl 5.10.Il \g{-1} si riferisce al gruppo di acquisizione immediatamente precedente:

use 5.010; 
$str =~ s/ 
     \b 
     (
     (\w+) 
     (?: 
      \s+ 
      \g{-1} 
      \b 
     )+ 
    ) 
    /[\1]/xg; 

conteggio non è così eccezionale, così posso usare gli incontri etichettati:

use 5.010; 
$str =~ s/ 
     \b 
     (
     (?<word>\w+) 
     (?: 
      \s+ 
      \k<word> 
      \b 
     )+ 
    ) 
    /[\1]/xg; 

posso etichettare la prima cattura ($1) e accedere al suo valore in %+ tardi:

use 5.010; 
$str =~ s/ 
     \b 
     (?<dups> 
     (?<word>\w+) 
     (?: 
      \s+ 
      \k<word> 
      \b 
     )+ 
    ) 
    /[$+{dups}]/xg; 

non avrei davvero bisogno che prima cattura anche se dal momento che è in realtà solo t qui per fare riferimento a tutto ciò che corrisponde. Purtroppo, sembra che ${^MATCH} non sia impostato abbastanza presto da consentirmi di utilizzarlo nella parte di sostituzione. Penso che sia un bug. Questo dovrebbe funzionare, ma non lo fa:

$str =~ s/ 
     \b 
     (?<word>\w+) 
     (?: 
      \s+ 
      \k<word> 
      \b 
     )+ 
    /[${^MATCH}]/pgx; # DOESN'T WORK 

Sto controllando questo su bCavo, ma che sta andando a prendere un po 'di tempo per compilare il mio piccolo macchina.

+2

+1 per trovare un bug in perl. –

0

Provare quanto segue:

$str =~ s/\b(\S+)\b(\s+\1\b)+/[\1]/g; 
Problemi correlati