Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks !

Searching for a number, followed by a char, followed by the same number is easy:

m/(\d).\1/

But how to search for a number, followed by a char, followed by the same number increased by one (\1+1) ?

So valid would be:

3x4, 5a6

Many thanks for your help !!

Replies are listed 'Best First'.
Re: arithmetic in a regex ?
by choroba (Cardinal) on Nov 13, 2023 at 10:26 UTC
    It is possible using the postponed regular subexpression.
    /([0-8])[a-z](??{ $1 + 1 })/

    See perlre for details.

    Updated: Simplified, don't use named capture groups.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      Thats brilliant.

      Now I have something to work on.

      MANY THANKS

Re: arithmetic in a regex ?
by GrandFather (Saint) on Nov 13, 2023 at 08:53 UTC

    Actually, the better question we haven't asked is: "Why?". Maybe a regex is not the best way to solve the problem, whatever it is. If we know why we may be able to offer a better solution.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

      I try to combine a coding in a two dimensional room (x,y). Explaining all the details would not help here. If a simple modification in the search string would be possible, I guess the problem could be solved quite elegant (like the e modifier). But I am not aware if this is possible. So i generated a simplified question. How to write a function, solving this is clear for me. But as usual, I try to solve it elegant and also learn something new.

      Thanks ALL for your help and time !!
Re: arithmetic in a regex ?
by afoken (Chancellor) on Nov 13, 2023 at 09:18 UTC

    I would search for a number followed by a char followed by another number using a regexp, and then filter in perl:

    #!/usr/bin/perl use strict; use warnings; use feature 'say'; my $text='abc 1foo 1x1 ee2 3B4 n 5 6t7 q9q 5+6'; while ($text=~/(\d)([[:alpha:]])(\d)/g) { if ($1 + 1 == $3) { say "$1$2$3 is wanted because $1 + 1 = $3"; } else { say "$1$2$3 matches, but is not wanted ($1 + 1 != $3)" +; } }

    Output:

    1x1 matches, but is not wanted (1 + 1 != 1) 3B4 is wanted because 3 + 1 = 4 6t7 is wanted because 6 + 1 = 7

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: arithmetic in a regex ?
by Tux (Canon) on Nov 13, 2023 at 08:26 UTC

    Should that include double digits? 9w10?

    Should it match if the digit/number before the letter is preceded by a digit? 13s4

    Should it match if the digit/number after the letter is followed by a digit? 3s44


    Enjoy, Have FUN! H.Merijn

      one digit only.

      so 9w10 is not valid, as 1 is not 9+1

      13s4 => match would find "3s4"

      3s44 => match would find "3s4"

        For the 9 cases, I would simply enumerate them:

        /( (0[a-z]1) |(1[a-z]2) |(2[a-z]3) |(3[a-z]4) |(4[a-z]5) |(5[a-z]6) |(6[a-z]7) |(7[a-z]8) |(8[a-z]9) )/x

        For further experimentation, I would write a test rig like the following to easily play with regular expressions and data and see how things work:

        #!perl use 5.020; use Test2::V0 '-no_srand' => 1; my @cases = ( # case, expected result, todo text ['13s4', '3s4' ], ['3s44', '3s4' ], ['0a1', '0a1' ], ['0a2', undef ], ); for my $case (@cases) { my( $line, $expected, $todo ) = @$case; my ($result) = $line =~ /( (0[a-z]1) |(1[a-z]2) |(2[a-z]3) |(3[a-z]4) |(4[a-z]5) |(5[a-z]6) |(6[a-z]7) |(7[a-z]8) |(8[a-z]9) )/x; my $t; if ($todo){ $t = todo( $todo ) }; is( $result, $expected, $line ); } done_testing;

        Not elegant, but fits the spec:

        /0.1|1.2|2.3|3.4|4.5|5.6|6.7|7.8|8.9|9.0/
        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: arithmetic in a regex ?
by afoken (Chancellor) on Nov 13, 2023 at 09:24 UTC

    Searching for a number, followed by a char, followed by the same number is easy:

    m/(\d).\1/

    That also matches 111:

    $ perl -E 'say "match" if "111"=~/(\d).\1/' match $

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)