in reply to howto make a very long IF statment shorter

How about

if ( q{abcdefgh} =~ /(?:$a|$b|$c)/ ) { # Do something }

I've tested it briefly and it seems to work ok.

Cheers,

JohnGG

Replies are listed 'Best First'.
Re^2: howto make a very long IF statment shorter
by ikegami (Patriarch) on Jun 29, 2006 at 21:51 UTC

    No good. "b matches a" doesn't necessarily follow from "a matches b". In fact, when it does, you should be using eq, not a regexp.

    use strict; use warnings; my $var_a = ''; my $var_b = 'abc'; my $var_c = ''; if ( $var_a =~ /abcdefgh/ || $var_b =~ /abcdefgh/ || $var_c =~ /abcdefgh/ ) { print("orig: true\n"); } else { print("orig: false\n"); } if ( q{abcdefgh} =~ /(?:$var_a|$var_b|$var_c)/ ) { print("johngg: true\n"); } else { print("johngg: false\n"); }
    outputs
    orig: false johngg: true
      That's a pity. My testing was brief because I was about to leave for a long motorcycling weekend. I've had a look again on my return and it seems that my method would only work if I add anchors to the match. In that case it would only be equivalent to the exact match if ( $var_a =~ /^abcdefgh$/ || ... and not the more general match of the OP. Here is a modified version

      use strict; use warnings; my $w = q{}; my $x = q{}; my $y = q{}; my $z = q{}; cmpOr(); $x = q{abc}; cmpOr(); $z = q{abcdefghij}; cmpOr(); $z = q{abcdefgh}; cmpOr(); $y = q{abcdefgh}; cmpOr(); $z = q{abcdefghij}; cmpOr(); sub cmpOr { print qq{Comparing OR methods with:-\n}, qq{ \$w is ->$w<-\n}, qq{ \$x is ->$x<-\n}, qq{ \$y is ->$y<-\n}, qq{ \$z is ->$z<-\n}; if ($w =~ /abcdefgh/ || $x =~ /abcdefgh/ || $y =~ /abcdefgh/ || $z =~ /abcdefgh/) { print qq{ orig: true\n}; } else { print qq{ orig: false\n}; } if (q{abcdefgh} =~ /^(?:$w|$x|$y|$z)$/) { print qq{johngg: true\n}; } else { print qq{johngg: false\n}; } print qq{\n}; }

      When run this produces

      In the particular circumstance of wanting each variable to match the string exactly, this method could save a deal of typing but it's no use in the general case as you pointed out.

      Just out of curiosity I had a try at an alternative to if ( $var_a =~ /^abcde$/ && $var_b =~ /^abcde$/ && .... This is what I came up with.

      if (q{abcde} =~ /^(?=$var_a$)(?=$var_b$)(?=$var_c$)/)

      Cheers,

      JohnGG

        Yes,
        if ( $var_a =~ /^abcde$/ && $var_b =~ /^abcde$/ && ....
        is not equivalent to
        if (q{abcde} =~ /^(?=$var_a$)(?=$var_b$)(?=$var_c$)/)
        but it is equivalent to
        if (q{abcde} =~ /^(?=\Q$var_a\E$)(?=\Q$var_b\E$)(?=\Q$var_c\E$)/)
        Of course, that only works because abcde meets the following conditions:

        • abcde doesn't contain any characters with special meanings to regexps.
        • You're matching the entire string.

        In other words, your "optimization", aside from being hard to read and probably being slower, has very limited usage.

        It would be better to use:

        my $match = 1; foreach ($var_a, $var_b, $var_c) { next if /abcdefgh/; $match = 0; last; } if ($match) { ... }

        or

        if ((grep /abcdefgh/, $var_a, $var_b, $var_c) == 3) { ... }

        or

        use List::MoreUtils qw( all ); if (all { /abcdefgh/ } $var_a, $var_b, $var_c) { ... }

        The grep solution is easier to read than the foreach solution, but it has the disadvantage of always executing the regexp for every item in the list. The foreach and the all solutions execute the regexp as few times as possible

        (Pardon the lateness of my reply; I was on vacation.)