Home > front end >  How to shorten this Perl expression
How to shorten this Perl expression

Time:01-13

I wrote the code below to cheat on Wordle (I am not good at it). Is there a way of combining the following part into single regex statement:

($word =~ m/c/i) and 
($word =~ m/a/i) and
($word =~ m/o/i)

That is to find the words containing all three letters 'c','a','o', in any order.

#!/usr/bin/perl
use 5.30.3;
use warnings;

my $dic_file = "/usr/share/dict/web2";
open (IN,"<", $dic_file) or die "Cannot open file.\n $!";

while (my $word=<IN>){
    chomp $word;
    if (length($word) == 5){        
        if(     ($word !~ m/[rtn]/i) and 
                ($word =~ m/c/i) and 
                ($word =~ m/a/i) and
                ($word =~ m/o/i)
          ){
                say $word; 
            }

    }
}

CodePudding user response:

You can get great gains by using $_ instead of $word.

my $dic_file = "/usr/share/dict/web2";

open( my $fh, "<", $dic_file )
   or die( "Can't open `$dic_file`: $!\n" );

while ( <$fh> ) {
   chomp;
   say if length == 5 && !/[rtn]/i && /c/i && /a/i && /o/i;
}

It is possible to get "and" out of regex using lookaheads.

my $dic_file = "/usr/share/dict/web2";

open( my $fh, "<", $dic_file )
   or die( "Can't open `$dic_file`: $!\n" );

while ( <$fh> ) {
   chomp;
   say if /^(?=.*c)(?=.*a)(?=.*o)[^rtn]{5}\z/si;
}

You can easily write this as a one-liner.

perl -nle'print if /^(?=.*c)(?=.*a)(?=.*o)[^rtn]{5}\z/si' /usr/share/dict/web2
  • Related