Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re^2: RegEx Question

by yoda54 (Monk)
on Sep 09, 2009 at 20:06 UTC ( [id://794442]=note: print w/replies, xml ) Need Help??


in reply to Re: RegEx Question
in thread RegEx Question

Thanks for the reply. I like to match permutations of 0-8 with each digits occurring once using all 8 digits. I've tried something like the follow but I can't get it straight... :(
[0-8]{1, 1}

Replies are listed 'Best First'.
Re^3: RegEx Question
by CountZero (Bishop) on Sep 09, 2009 at 21:28 UTC
    [0-8]{1, 1} matches one digit out of the set {0 1 2 3 4 5 6 7 8}, so it doesn't do what you need at all.

    Actually, I am not sure that you can do this in one regex.

    I will show a simpler example only using permutations of the digits 0 - 3 (to make it easier to follow):

    First you have to check that your string contains 4 digits in the range 0 - 3. That one is easy: /^[0-3]{4}$/

    If your string passes this test, then you check whether each digit occurs only once.

    /^(\d)(?!\d*\1)(\d)(?!\d*\2)(\d)(?!\d*\3)\d$/;
    This works by capturing each digit and using negative look-aheads to check that this digit does not re-occur again in the string.

    The following program proves that it works:

    use warnings; use strict; for my $one (0 .. 3) { for my $two (0 .. 3) { for my $three (0 .. 3) { for my $four (0 .. 4) { my $test = "$one$two$three$four"; print "$test\n" if $test=~m/^[0-3]{4}$/ and $test=~m/^ +(\d)(?!\d*\1)(\d)(?!\d*\2)(\d)(?!\d*\3)\d$/; } } } }
    Output:
    0123 0132 0213 0231 0312 0321 1023 1032 1203 1230 1302 1320 2013 2031 2103 2130 2301 2310 3012 3021 3102 3120 3201 3210

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      Actually, I am not sure that you can do this in one regex.

      Assuming he meant all 9 digits,

      / ^ (?=[0-8]{9}\z) (?=.*0) (?=.*1) (?=.*2) (?=.*3) (?=.*4) (?=.*5) (?=.*6) (?=.*7) (?=.*8) /sx;
        Very well done! A Regex which consists of nothing but an anchor and lookaheads. It takes true greatness to think of such a thing.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      Thanks for the reply... I was really hoping for a easy way out...!! :)

        It depends a great deal on what you consider to be 'easy' and probably also it depends what it is that you actually want to achieve. The following code may help:

        use strict; use warnings; for my $number (1233456, 10, 1, 555789041) { my %digits; my @failDigits = grep {++$digits{$_} == 2} split '', $number; next if ! @failDigits; print "Number $number failed for:\n"; print " $_: $digits{$_} places\n" for @failDigits; }

        Prints:

        Number 1233456 failed for: 3: 2 places Number 555789041 failed for: 5: 3 places

        True laziness is hard work
Re^3: RegEx Question
by graff (Chancellor) on Sep 09, 2009 at 23:41 UTC
    I like to match permutations of 0-8 with each digits occurring once using all 8 digits.

    Um... the way I learned it, "0-8" represents 9 digits. (1-8 would be 8 digits, as would 0-7.) Is there some digit between 0 and 8 that you intend to leave out, and if so, which one?

    Anyway, if you had said "permutations of 0-8 with each digit occurring once, using all 9 digits", then I would understand that you are looking only for strings of nine digit characters, such that all nine characters are distinct, and none of them is the digit "9":

    #!/usr/bin/perl use strict; while (<DATA>) { chomp; if ( length() == 9 and not ( /[^0-8]/ or /(.).*\1/ )) { print "$_\n"; } else { warn "rejected input: $_\n"; } } __DATA__ 01234 123456780 1234567890 223456781 345678012 234567890 a12345678 012345678 456782011 456782013
    Update: I suspect that the regex used as the last stage in my conditional is a fairly expensive operation; for strings that actually meet the criteria (are not rejected), it has to do 8+7+6+...+1 (total of 36) character comparisons to finish. (There should be some sort of "O(...n...)" expression for that, but it escapes me.) So, it would most likely be better to use a split/hash solution, as suggested by others, especially if you'll be handling large quantities of input with a relatively high "success" rate. Something like this:
    while (<DATA>) { chomp; if ( length() == 9 and not /[^0-8]/ ) { my %c = map { $_ => undef } split //; if ( keys %c == 9 ) { print "$_\n"; next; } } warn "rejected input: $_\n"; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://794442]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-24 05:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found