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

Hi Monks!
I have an array with account numbers in it, and I am trying to separate the array elements using some reg. exp. My question is why is the first IF result showing second and I am looking for it first in my code, please any help why, here is the samplecode:
my @account = qw(34765-22333-333489-99867-22340-23456-3229 XLM8876 AMP +7765 WQP22349); my @chk_acc = split('-',@account); foreach my $checked (@chk_acc) { chomp(); if($checked=~/^(\w{3})(\d{4,7})/ig) { # it should print the accounts starting with letters here print "*$checked*<br>"; }else{ # else the rest of the accounts not starting with any l +etters print"-$checked-<br>"; } }

Thanks!

Replies are listed 'Best First'.
Re: Regular Exp. in foreach loop Help!
by toolic (Bishop) on Feb 25, 2010 at 17:12 UTC
    I have no idea what your question is, but, do you realize
    my @chk_acc = split('-',@account);
    is effectively
    my @chk_acc = split('-',4);
    Typically, you would use a scalar, not an array, as input to split. The array is being evaluated in scalar context, which results in the size of the array (4).

    Also, use strict and warnings because warnings will give you other useful info.

    perltidy can help the indenting-impaired :)

Re: Regular Exp. in foreach loop Help!
by tilly (Archbishop) on Feb 25, 2010 at 17:56 UTC
    I believe I understand your confusion. Output happens not according to what comes first in your code, but what is executed first in your code. When you loop over an array you will process each element in turn. So you get the first element's output, the second element's output, etc. This has everything to do with how your data is organized, not your code.

    If you wish to reorder your output you need to reorder your data. For that you can collect data into data structures as you go through the array. Then process the data structures at the end.

    Here are some further points of potential confusion that I see in your code.

    • You are passing @account where a scalar is expected. My map statement is more likely to do what you want.
    • You are putting array elements in $checked then not specifying what to chomp, so it chomps $_. Nothing is in $_ so that is useless.
    • 0-9 match \w so your regular expression will match 7 digit numbers. This is may surprise you at some point. Hence my changed regular expression.
    • The i and g modifiers to your regular expression are doing nothing and hence may surprise you.
    • Your code comments suggest that you expect multiple elements to be output together when you are printing them one element at a time. If so you have a lot of confusion around what iteration is and how it works. (Which fits with my understanding of your initial question.)
    Here is some code that might do something more like what you want.
    my @account = qw( 34765-22333-333489-99867-22340-23456-3229 XLM8876 AMP7765 WQP22349 ); my @account_starting_with_digit; my @account_starting_without_digit; for my $checked (map {split /-/, $_} @account) { if ($checked =~ /^\d/) { push @account_starting_with_digit, $checked; } else { push @account_starting_without_digit, $checked; } } print "*" . (join " ", @account_starting_without_digit) . "*<br>\n"; print "-" . (join " ", @account_starting_with_digit) . "-<br>\n";
    If you wish further help I strongly suggest that in addition to showing your code (which is a good step) you actually show the output you were hoping that your code would produce but didn't. This would greatly clarify what you want, particularly if it is very different from what your code does.
Re: Regular Exp. in foreach loop Help!
by Ratazong (Monsignor) on Feb 25, 2010 at 17:20 UTC

    • Try to split a string, not an array
    • Your source data is only partly separated with "-"

    my $account = "34765-22333-333489-99867-22340-23456-3229-XLM8876-AMP77 +65-WQP22349"; my @chk_acc = split("-",$account);

    HTH, Rata (wondering about the useless chomp() ... not the first time today ...)

Re: Regular Exp. in foreach loop Help!
by jwkrahn (Abbot) on Feb 25, 2010 at 17:52 UTC
    foreach my $checked (@chk_acc) { chomp();

    chomp() is short for chomp( $_ ) but you don't assign any value to $_ so the use of chomp there is superfluous.

    if($checked=~/^(\w{3})(\d{4,7})/ig) { # it should print the accounts starting with letters here

    The \w character class matches all upper case letters and all lower case letters and all digits and the '_' character so the use of the /i option is superfluous and the comment is wrong because \w will also match digits and '_'.    The regular expression is anchored at the beginning of the string in $checked so it will only match once so the use of the /g is also superfluous.    You are also capturing two strings which you aren't using so the capturing parentheses are also superfluous.    So, to sum up, you probably want something like:

    if ( $checked =~ /^[[:alpha:]]{3}\d{4,7}/ ) { # it should print the accounts starting with letters here
Re: Regular Exp. in foreach loop Help!
by cdarke (Prior) on Feb 25, 2010 at 17:34 UTC
    I'm guessing that each set of numbers are accounts, as are the names. In other words, some accounts are concatenated with '-' (guess). You could use a scalar rather than an array to hold your data and split around [ -] (that's a space OR a hyphen). You might not have that option, so, with minimum alterations to your code:
    use warnings; use strict; my @account = qw(34765-22333-333489-99867-22340-23456-3229 XLM8876 AMP +7765 WQP22349); my @chk_acc = map {split('-')} @account; foreach my $checked (@chk_acc) { # chomp(); if ($checked =~ /^(\w{3})(\d{4,7})/ig) { # it should print the accounts starting with letters here print "*$checked*<br>"; } else { # else the rest of the accounts not starting with any letters print"-$checked-<br>"; } }
    Gives:-34765-<br>-22333-<br>-333489-<br>-99867-<br>-22340-<br>-23456-<br>-3229-<br>*XLM8876*<br>*AMP7765*<br>*WQP22349*<br>

    Update: Your RE is more complex that it need be (unless you are not showing us the whole story):
    if ($checked =~ /^\w{3}\d{4,7}/)
    should be sufficient (\w includes upper and lowercase characters). However, what if there are more than 7 digits following? This RE would still match, did you mean /^\w{3}\d{4,7}$/?