s/// has apparent side effect on grep()

Discussion in 'Perl' started by John E. Jardine, Apr 12, 2004.

  1. Hi,

    Problem:
    Executing 's///' has a side effect on grep null string matching.
    If line 62, the substitution, is executed the last two values returned by
    grep and printed on lines 68, 69 are different than the values returned and
    printed when line 62 is commented out. Line 62 shouldn't have any impact on
    lines 67,68 & 69.

    Environment:
    (1) Reproducable under Perl 5.6.1 running on Linux 2.4.5 (Slackware 8.0
    installation) Pentium MMX/166MHz, 96MB Ram.
    (2) Reproducable under Perl 5.8.0 running on Linux 2.6.5 (Slackware 9.1.0
    installation) AMD Athlon 64 3000+, 1GB Ram

    To reply by e-mail, remove the dot-baseball treat-dot from my e-mail address

    Example Code:
    #!/usr/bin/perl -w
    my $item;
    my $fltr_expr;
    my $fltr_attr1;
    my $fltr_op1;
    my $fltr_val1;
    my $fltr_attr2;
    my $fltr_op2;
    my $fltr_val2;
    my $fltr_attr3;
    my $fltr_op3;
    my $fltr_val3;
    my @test_data = ();
    my %fltr_num_ops;
    my %fltr_str_ops;
    my %card_columns = (network => "network_srname",
    node => "node_srname",
    nodetype => "node_srtype",
    area => "node_lata",
    cardtype => "srcardtype");


    $fltr_num_ops{EQUAL} = " == ";
    $fltr_num_ops{NOTEQUAL} = " != ";
    $fltr_num_ops{LIKE} = " =~ m// ";
    $fltr_num_ops{NOTLIKE} = " !~ m// ";
    $fltr_str_ops{EQUAL} = " eq ";
    $fltr_str_ops{NOTEQUAL} = " ne ";
    $fltr_str_ops{LIKE} = " =~ m// ";
    $fltr_str_ops{NOTLIKE} = " !~ m// ";

    #------------------------------------------------------------------------
    # Test data normally retrieved from database. This accurately represents
    # the problem though.
    #------------------------------------------------------------------------
    push(@test_data, "cardtype|LIKE|HUB|||||||");
    push(@test_data, "cardtype|EQUAL|CC2|||||||");
    foreach $item (@test_data) {
    ( $fltr_attr1, $fltr_op1, $fltr_val1, $fltr_attr2, $fltr_op2, $fltr_val2,
    $fltr_attr3, $fltr_op3, $fltr_val3 ) = split(/\|/, $item);

    $fltr_attr1 =~ tr/A-Z/a-z/;
    $fltr_attr1 =~ s#^\s*(\S*)\s*$#$1#;
    $fltr_op1 =~ s#^\s*(\S*)\s*$#$1#;
    $fltr_val1 =~ s#^\s*(\S*)\s*$#$1#;

    #---------------------------------------------------------------------
    # $fltr_attr2, $fltr_op2, fltr_val2, $fltr_attr3, $fltr_op3, fltr_val3
    # are not processed in this example - normally they would've been.
    #---------------------------------------------------------------------
    $fltr_expr = "";
    if( $fltr_val1 =~ m#^\d+$# ) {
    $fltr_expr = qq{$fltr_attr1 $fltr_num_ops{$fltr_op1} $fltr_val1}; }
    else {
    $fltr_expr = qq{$fltr_attr1 $fltr_str_ops{$fltr_op1} "$fltr_val1"}; }

    #---------------------------------------------------------------------
    # This is where the problem is. Try (un)commenting out the
    # middle line (substitution). It changes the results of the grep()s
    # in the next section.
    #---------------------------------------------------------------------
    print "Before Substitute: '$fltr_expr'\n";
    # $fltr_expr =~ s#m// +"*([^"]+)"*#m/$1/#g;
    print "After Substitute: '$fltr_expr'\n";

    print
    "$fltr_attr1|$fltr_op1|$fltr_val1|$fltr_attr2|$fltr_op2|$fltr_val2|$fltr_att
    r3|$fltr_op3|$fltr_val3\n";

    print sprintf("grep(/$fltr_attr1/, keys %%card_columns) = %d\n",
    scalar(grep(/$fltr_attr1/, keys %card_columns)));
    print sprintf("grep(/$fltr_attr2/, keys %%card_columns) = %d\n",
    scalar(grep(/$fltr_attr2/, keys %card_columns)));
    print sprintf("grep(/$fltr_attr3/, keys %%card_columns) = %d\n",
    scalar(grep(/$fltr_attr3/, keys %card_columns)));
    print "fltr_attr1 = '$fltr_attr1'\n";
    print "fltr_op1 = '$fltr_op1'\n";
    print "fltr_val1 = '$fltr_val1'\n";
    print "fltr_attr2 = '$fltr_attr2'\n";
    print "fltr_op2 = '$fltr_op2'\n";
    print "fltr_val2 = '$fltr_val2'\n";
    print "fltr_attr3 = '$fltr_attr3'\n";
    print "fltr_op3 = '$fltr_op3'\n";
    print "fltr_val3 = '$fltr_val3'\n";
    foreach (keys %card_columns) {
    print "'$_' = '$card_columns{$_}'\n"; }
    print "\n";
    }
    John E. Jardine, Apr 12, 2004
    #1
    1. Advertising

  2. John E. Jardine

    Joe Smith Guest

    John E. Jardine wrote:

    > Executing 's///' has a side effect on grep null string matching.


    That is correct. It is documented behavior.

    If the PATTERN evaluates to the empty string, the last success-
    fully matched regular expression is used instead.

    You need to change lines 67-69 in your program to

    printf("grep(/$fltr_attr1/, keys %%card_columns) = %d\n",
    scalar(grep(/$fltr_attr1/, keys %card_columns))) if $fltr_addr1 ne "";
    printf("grep(/$fltr_attr2/, keys %%card_columns) = %d\n",
    scalar(grep(/$fltr_attr2/, keys %card_columns))) if $fltr_addr2 ne "";
    printf("grep(/$fltr_attr3/, keys %%card_columns) = %d\n",
    scalar(grep(/$fltr_attr3/, keys %card_columns))) if $fltr_addr3 ne "";

    -Joe
    Joe Smith, Apr 12, 2004
    #2
    1. Advertising

  3. John E. Jardine

    John Jardine Guest

    Hi Joe,

    My bad - I must have missed that and simply never hit the issue before.
    Thanks for clearing it up for me.

    Cheers,
    J.J.

    On Mon, 12 Apr 2004, Joe Smith wrote:

    >John E. Jardine wrote:
    >
    >> Executing 's///' has a side effect on grep null string matching.

    >
    >That is correct. It is documented behavior.
    >
    > If the PATTERN evaluates to the empty string, the last success-
    > fully matched regular expression is used instead.
    >
    >You need to change lines 67-69 in your program to
    >
    >printf("grep(/$fltr_attr1/, keys %%card_columns) = %d\n",
    >scalar(grep(/$fltr_attr1/, keys %card_columns))) if $fltr_addr1 ne "";
    >printf("grep(/$fltr_attr2/, keys %%card_columns) = %d\n",
    >scalar(grep(/$fltr_attr2/, keys %card_columns))) if $fltr_addr2 ne "";
    >printf("grep(/$fltr_attr3/, keys %%card_columns) = %d\n",
    >scalar(grep(/$fltr_attr3/, keys %card_columns))) if $fltr_addr3 ne "";
    >
    > -Joe
    >
    John Jardine, Apr 13, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Shari

    Apparent session crosstalk

    Shari, Sep 24, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    430
    Shari
    Oct 1, 2004
  2. Guest
    Replies:
    4
    Views:
    417
    Guest
    Jan 28, 2005
  3. Replies:
    2
    Views:
    317
  4. Isaac Grover
    Replies:
    6
    Views:
    532
    Spartanicus
    Feb 1, 2004
  5. Bengt Richter
    Replies:
    3
    Views:
    288
    Steve Holden
    Jan 19, 2005
Loading...

Share This Page