http://www.perlmonks.org?node_id=213188

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

I'm working on the regular Perl Quiz of the Week, and while I've got it solved, I don't understand why I had to do something to dwiw. The included code shows the pertinant problem.

I take a line of the box to be put into the output. $putNum is a boolean variable. The problem is that instead of updating $boxLine with the current word number, it continues to put in the number 1.

The problem went away if I instead use a seperate variable in the foreach line and then later assign its value to $boxLine.

Please help me understand why this is happening.

my $wordNum = 0; foreach my $boxLine ( @empty_square) { if ($putNum) { $wordNum ++; my $space = $boxLine =~ s/\./\./g; my $string = sprintf "%-*d", $space, $wordNum; $boxLine =~ s/\.+/$string/o; } else { $boxLine =~ s/\./ /g; } }

Replies are listed 'Best First'.
Re: Question of variable interpolation in regex
by tommyw (Hermit) on Nov 15, 2002 at 16:51 UTC

    This line $boxLine =~ s/\.+/$string/o; uses the /o modifier, so the regular expression is only compiled once. That is, even if the value of $string changes, the regular expression won't reflect that. So the first time through, it compiles as s/\.+/    1/o and never changes again.

    updated: Apparently, I'm talking rubbish. Sorry!

    --
    Tommy
    Too stupid to live.
    Too stubborn to die.

      Actually, the left-hand side of the substitution (the regex) is the part that is only compiled once. The right-hand side will change as $string changes. Try this:
      my $foo = 'a'; for my $string ('b'..'z') { $foo =~ s/./$string/o; print "$foo\n"; }

      -- Mike

      --
      just,my${.02}

Re: Question of variable interpolation in regex
by SparkeyG (Curate) on Nov 15, 2002 at 16:56 UTC
    A few people commented that I wasn't clear in my question and also asked for example input and output. The input in this loop is:
    my @empty_square = qw(+----+ |....| |....| |....| +----+ );
    We iterate over several of these boxes, and need to replace . with spaces and a number in the upper left hand corner. I have some logic, that isn't included hear, to determine when to add the number.

    The desired output of this loop would be if $putNum is true, the replace |....| with |1   | the first time, |2   | the second, etc. However, all it does now, if $putNum is true, it replaces all |....| with |1   |.

    I can fix this if I replace the following:

    foreach my $boxLine ( @empty_square) {
    with
    foreach my $line ( @empty_square) { my $boxLine = $line;
    I hope this makes it clearer. --Sparkey
      Ok I saw a couple of things..

      1) In your code you incremented your value even though the first line doesnt match "/\./". So you always start at 2 instead of 1.
      2) you were using sprintf for your output when perl already had what you wanted to do built in via the nifty 'x' operator...

      I also changed the var names, just cause I could :)
      So here is what I came up with
      #!/usr/local/bin/perl -wT use strict; my($putNum,$line,$s_count,$num,$n_line, @square); $putNum = 1; @square = ( '+----+', '|....|', '|....|', '|....|', '+----+' ); foreach $line (@square) { if (!$putNum) { $line =~ s/\./ /g; } else { if ($line =~ /\./) { $s_count = $line =~ s/\./\./g; $num++ if ($s_count); $n_line = "$num" . ' ' x ($s_count - length($num)); $line =~ s/\.+/$n_line/o; } } print "$line\n"; } # OUTPUT +----+ |1 | |2 | |3 | +----+
      Is this what you were looking for? The same number of spaces that were previously '.'s on the line?

      Happy Hackin :)

      /* And the Creator, against his better judgement, wrote man.c */
        I solved the 1st problem you rose when $putNum is decided. If the line being considered is either the top or bottom line, $putNum is false.

        As to your second point, tmtowtdi. ;-)

        But I see I still haven't been clear. :-(
        the output I'm seeing is

        +----+----+----+----+ |1 |1 |1 |1 | | | | | | | | | | | +----+----+----+----+
        When what I want is
        +----+----+----+----+ |1 |2 |3 |4 | | | | | | | | | | | +----+----+----+----+
        Update:
        Take a look at my scratch pad for the full code
      Dunno, it works for me on perl 5.6.0, 5.6.1, and 5.8.0. Which version are you using?
      print join("\n", @empty_square), "\n"; +----+ |2 | |3 | |4 | +----+
Re: Question of variable interpolation in regex
by Thelonius (Priest) on Nov 15, 2002 at 22:40 UTC
    When what I want is +----+----+----+----+ |1 |2 |3 |4 | | | | | | | | | | | +----+----+----+----+
    Well, you'll need somthing like:
    while ($boxLine =~ s/(\.+)/sprintf("%-*d", length($1), $wordNum)/e) { $wordNum++ }
    But then you'll have to skip over the other lines which have blanks (you have multiple lines per square).