2012-06-21 8 views
14

Por ejemplo, la palabra desastre funcionaría debido Debac, pero lecho marino no funcionaría porque: 1. no hay c en ninguna secuencia de 5 caracteres que pueda formarse, y 2. la letra e aparece dos veces. Como otro ejemplo, comentarios funcionaría debido a edbac. Y recuerde, la solución debe hacerse usando solo expresiones regulares.Uso de expresiones regulares para buscar una palabra con las cinco letras ABCDE, cada letra aparece exactamente una vez, en cualquier orden, sin descansos entre

Una estrategia que intenté implementar fue: unir la primera letra si está dentro [a-e] y recordarla. Luego encuentra la siguiente letra en [a-e] pero no la primera letra. Y así. No estaba segura de lo que era la sintaxis (o incluso si existía alguna sintaxis) por lo que mi código no funcionó:

open(DICT, "dictionary.txt"); 
@words = <DICT>; 

foreach my $word(@words){ 

if ($word =~ /([a-e])([a-e^\1])([a-e^\1^\2])([a-e^\1^\2^\3])([a-e^\1^\2^\3^\4])/ 
){ 
    print $word; 
} 
} 

Yo también estaba pensando en utilizar (= expresiones regulares?) Y \ G, pero yo no estaba' t seguro cómo funcionaría.

Respuesta

15
/ 
    (?= .{0,4}a) 
    (?= .{0,4}b) 
    (?= .{0,4}c) 
    (?= .{0,4}d) 
    (?= .{0,4}e) 
/xs 

Es probable que se traduce en más rápido a juego para generar un patrón de todas las combinaciones.

use Algorithm::Loops qw(NextPermute); 
my @pats; 
my @chars = 'a'..'e'; 
do { push @pats, quotemeta join '', @chars; } while NextPermute(@chars); 
my $re = join '|', @pats; 

abcde | abced | abdce | abdec | ABECD | abedc | acbde | acbed | ACDBE | acdeb | acebd | acedb | adbce | adbec | adcbe | adceb | adebc | adecb | aebcd | AEBDC | aecbd | aecdb | aedbc | aedcb | bacde | baced | badce | badec | bacd | baedc | bcade | bcaed | bcdae | bcdea | bcead | bceda | bdace | bdaec | bdcae | bdcea | bdeac | bdeca | beacd | beadc | becad | becda | bedac | bedca | cabde | cab | cadbe | cadeb | caebd | caedb | cbade | cbaed | cbdae | cbdea | cbead | cbeda | cdabe | cdaeb | cdbae | cdbea | cdeab | cdeba | ceabd | ceadb | cebad | cebda | cedab | cedba | dabce | dabec | dacbe | daceb | daebc | daecb | dbace | dbaec | dbcae | dbcea | dbeac | dbeca | dcabe | dcaeb | dcbae | dcbea | dceab | dceba | deabc | deacb | debac | debca | decab | decba | eabcd | eabdc | eacbd | eacdb | eadbc | eadcb | ebacd | ebadc | ebcad | ebcda | ebdac | ebdca | ecabd | ecadb | ecbad | ecbda | ecdab | ecdba | edabc | edacb | edbac | edbca | edcab | edcba

(Esto se optimizará en un trie en Perl 5.10+. Antes de 5.10, utilice Regexp :: Lista.)

+1

+1 - Me gusta más que mi propia solución. Para explicar a los demás, los lookaheads garantizan que: en las siguientes 5 letras, haya al menos una 'a', al menos una 'b', al menos una 'c', al menos una 'd' y al menos una ' mi'. Dado que solo hay cinco "espacios", se garantiza que cada uno aparezca exactamente una vez. –

+0

Se agregó una solución alternativa. – ikegami

+0

La solución alternativa también funciona si quiere buscar material duplicado (p. Ej.abcdd en lugar de abcde) – ikegami

6
#! perl -lw 
for (qw(debacle seabed feedback)) { 
    print if /([a-e])(?!\1) 
     ([a-e])(?!\1)(?!\2) 
     ([a-e])(?!\1)(?!\2)(?!\3) 
     ([a-e])(?!\1)(?!\2)(?!\3)(?!\4) 
     ([a-e])/x; 
} 
7

Su solución es inteligente, pero por desgracia [a-e^...] no funciona, como lo encontró. No creo que haya una manera de mezclar clases de personajes regulares y negadas. No puedo pensar en una solución usando los símbolos de anticipación sin embargo:

/(([a-e])(?!\2)([a-e])(?!\2)(?!\3)([a-e])(?!\2)(?!\3)(?!\4])([a-e])(?!\2)(?!\3)(?!\4])(?!\5)([a-e]))/ 

lo ve aquí: http://rubular.com/r/6pFrJe78b6.

ACTUALIZACIÓN: Mob señala en los comentarios a continuación, que la alternancia se puede utilizar para compactar la anterior:

/(([a-e])(?!\2)([a-e])(?!\2|\3)([a-e])(?!\2|\3|\4])([a-e])(?!\2|\3|\4|\5)([a-e]))/ 

La nueva demo: http://rubular.com/r/UUS7mrz6Ze.

+0

Tenga en cuenta que no puede tener referencias en las clases de caracteres. De ahí la necesidad de múltiples referencias en lugar de algo como '' (?! [\ 2 \ 3 \ 4 \ 5]) ''. Además, tuve que comenzar a contar en 2 no 1 porque quería incluir un grupo de captura "general" para la demostración de rubular. –

+1

Pero puede usar la alternancia: '... (?! \ 2 | \ 3 | \ 4 | \ 5)' – mob

Cuestiones relacionadas