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

Hi there! First, thanks for considering my query! I'm currently making a little script (obviously in Perl) and I'm trying to make a regex. My problem is that even if it works, something bothers me: I want to control this:

GigabitEthernet1/0/1

with:

/(^gi.*)([1-8])(\/)(0)(\/)([1-9]|[1-3][0-9]|4[0-8])/i

I want to make a regex which blocks the user if he inputs something like that:

GigabitEthernet1/0/49

The maximum value of the number behind the last slash should be 48, but I cannot make. I don't want to make something like:

if ($6>48)....

Could you help me please? Thanks in advance!

Replies are listed 'Best First'.
Re: Regex : Limit value of a string
by hippo (Archbishop) on Oct 14, 2015 at 08:48 UTC

    The regex you are using does not anchor to the end.

    use strict; use warnings; use Test::More tests => 4; my $tomatch = 'GigabitEthernet1/0/48'; my $notmatch = 'GigabitEthernet1/0/49'; my $yourgo = qr/(^gi.*)([1-8])(\/)(0)(\/)([1-9]|[1-3][0-9]|4[0-8])/i; my $mygo = qr/(^gi.*)([1-8])(\/)(0)(\/)([1-9]|[1-3][0-9]|4[0-8])$/i; like ($tomatch, $yourgo, "$tomatch matches"); unlike ($notmatch, $yourgo, "$notmatch does not match"); like ($tomatch, $mygo, "$tomatch matches"); unlike ($notmatch, $mygo, "$notmatch does not match");

    There's other things you could clean up in the regex and your stipulation of not using a numerical comparison requires justification but this should put you on the right road at least.

      Man, thanks for your help! I was pretty sure I tried with the "$" at the end, but obviously not... Thanks a lot!

Re: Regex : Limit value of a string
by AppleFritter (Vicar) on Oct 14, 2015 at 09:29 UTC

    The following regex:

    /(^gi.*)([1-8])(\/)(0)(\/)([1-9]|[1-3][0-9]|4[0-8])/i

    aside from not anchoring to the end of the string, as hippo has pointed out, explicitely attempts to match numbers from 1 to 48 only, so using this to extract said number and then checking to see whether it's greater than 48 won't work. It won't be; if it were the regex wouldn't match in the first place.

    As an aside, is there a reason you're explicitely capturing the backslashes and the zero? I'm assuming not; I've removed those captures below, but if you need them after all for some reason just put them back in.

    Now, asides aside, since you don't want to explicitely check whether the number's greater than 48, you'll just want to match the regex against the user's input, and only proceed if it does (knowing then that the number does not exceed 48). And I'd do that anyway, since if the input you're matching against is supplied by the user, the rest of it may also not be what you expect, and explicit matching will make sure you're getting precisely what you expect.

    So just do something like this:

    # ... if($input =~ m/^(gi.*)([1-8])\/0\/([1-9]|[1-3][0-9]|4[0-8])$/i { my ($string, $digit, $number) = ($1, $2, $3); # e.g. "GigabitEther +net", "1" and "48"; $number will be at most 48 # ... }
Re: Regex : Limit value of a string
by LanX (Saint) on Oct 14, 2015 at 08:51 UTC
    Imho your if solution is the best readable.

    Hence better stick with it!

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      Wholeheartedly agree.   And here, to me, is why:   a regex pattern should match what the string looks like, and to extract pieces from it, whereas if/then logic should then be used to test for what those pieces contain.   Now, obviously, there are cases where certain digits of a string are known to serve only as identifiers of the string itself ... e.g. the leading digits of ISBNs for books ... but this is not such a case.   Someday it is quite likely that someone will want to change this logic, say to allow a different number to be in this position, or to allow more than one, or to add some other ruling constraint.   If you are doing this in the regex, you’re making a mess for that person.   :-)

Re: Regex : Limit value of a string
by Athanasius (Archbishop) on Oct 14, 2015 at 09:57 UTC

    Hello PtitePomme, and welcome to the Monastery!

    You’ve already received excellent answers; I just want to raise an issue that arises from your use of the special . character in the first capture: (gi.*). The expression .* matches any sequence of non-newline characters. So, even with an anchor to the end of the string, your regex will still match something like this:

    my $input = 'GigabitEthernet1/0/49xxx7/0/48';

    because (gi.*) will match GigabitEthernet1/0/49xxx.

    Now, maybe this isn’t a problem; but as a general principle I’d be more comfortable with a regex that specifies the exact pattern to be matched. Making the * quantifier non-greedy won’t help here. But you can exclude / characters from the first match:

    if ($input =~ m{ ^ (gi [^/]*) ([1-8]) / 0 / ([1-9] | [1-3][0-9] | 4[0- +8]) $ }ix) {

    The first capture here is gi (any case) followed by a sequence of non-slash characters. Too fussy? Perhaps, but then — better safe than sorry!

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: [SOLVED] Regex : Limit value of a string
by johngg (Canon) on Oct 14, 2015 at 14:46 UTC

    I don't think any of the proposed solutions will reject GigabitEthernet31/0/23 as the (^gi.*)([1-8]), ^(gi.*)([1-8]) or ^ (gi [^/]*) ([1-8]) will all capture GigabitEthernet3 into $1 and 1 into $2. You need to anchor the start of the first digit as well as the end of the last. Also simpler to construct the regex using a range and locally setting $".

    $ perl -Mstrict -Mwarnings -E ' my $regex = do { my @range1 = 1 .. 8; my @range2 = 1 .. 48; local $" = q{|}; qr{(?x) ^ GigabitEthernet ( @range1 ) / 0 / ( @range2 ) $ }; }; say $regex; say qq{$_: }, m{$regex} ? q{MATCHED} : q{FAILED} for qw{ GigabitEthernet1/0/48 GigabitEthernet1/0/49 GigabitEthernet1/0/236 GigabitEthernet31/0/48 GigabitEthernet3/0/13 };' (?^u:(?x) ^ GigabitEthernet ( 1|2|3|4|5|6|7|8 ) / 0 / ( 1|2|3|4|5|6|7| +8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31 +|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48 ) $ ) GigabitEthernet1/0/48: MATCHED GigabitEthernet1/0/49: FAILED GigabitEthernet1/0/236: FAILED GigabitEthernet31/0/48: FAILED GigabitEthernet3/0/13: MATCHED $

    I hope this is helpful.

    Cheers,

    JohnGG

Re: [SOLVED] Regex : Limit value of a string
by Discipulus (Canon) on Oct 14, 2015 at 10:43 UTC
    welcome PtitePomme

    you got good answers and if you like to play with regexes see some way to do it at Re^3: Text filTer and assign - regex tools

    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.