Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Re: Stupid mistakes I repeatedly make

by rg0now (Chaplain)
on Mar 27, 2005 at 10:04 UTC ( #442604=note: print w/replies, xml ) Need Help??

in reply to Stupid mistakes I repeatedly make

No matter how often I remind myself that s/// does not return the string, my fingers still type the code as if it does.

This problem becomes even more notorious, when you have to use PHP once in a while, and you get used to the familiar behavior of preg_replace. preg_replace does exactly what you wrote, that is, it returns the replaced string. I know, it has come up before many times here, but for me that PHP-ish behavior is much more natural. This does not generalize to PHP itself, though...


Replies are listed 'Best First'.
Re^2: Stupid mistakes I repeatedly make
by dragonchild (Archbishop) on Mar 28, 2005 at 13:48 UTC
    Just out of off-topic curiousity - how does PHP let you know how many things were replaced?

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      Just to follow this thread off-topic ... how often does it matter? I can't even think of any time where I cared how many items were replaced with s///. And it's almost never when I don't care about the resultant string. So, yes, I'd agree that PHP's method is as flexible as Perl's, but I would suggest that the s operator is not Huffman-coded properly. The thing that we do most often (care about the resultant string) is the most work. Even if the difference is minor (an extra set of parens), Larry seems to talk a lot about "natural language" for perl 6, and I'd suggest that the current syntax is less natural. If, for example, s/// returned the resultant string in scalar context and the list of substitutions in list context, you could get the number of substitutions with my $num = @{[s/$re/foo/g]}; (although that syntax is probably not so ugly in perl 6 either). Given the rareness of its use (if my experience is any indication, or even in the same ballpark as reality in general), I think this would make more sense.

      I seem to recall that perl6 is supposed to solve all of this, so not only is this thread off-topic, but probably moot anyway ;-)

        I've often seen code that, although it doesn't care about the exact number of replacements, it cares about whether a replacement was made (the number would be 0 or 1 since it's not a global replacement). This is typically used for tokenizing by deleting the tokens from a string (note: this might not very efficient for long strings!). The following is a simple example for tokenizing a space-delimited list of numbers.
        $s = "213 3218 213"; while ($s =~ s/^(\d+)\s*//) { print "$1\n"; } if (length $s) { print "Error! didn't expect this: '$s'\n"; }

        This contrived example could probably be done more simply in other ways, but for more complicated tokenizers it is not such a bad approach.

        You likely don't care how many times the replacement happened, but it's not uncommon to care about whether any replacements happened.
        if (s/foo/bar/) { ... } else { ... }
        (How many isn't even an issue unless you're using /g. It's just 1 or 0 — it replaced something or it didn't.)

        Caution: Contents may have been coded under pressure.
        I've use this in my code before:
        #actual data came over the network with inconstant line ends. my $text = "some\r\nmulti-line\ntext"; my $line_count = $text =~ s/\r?\n/\n/g;
        There were cenrtanly a dozen other ways to get the line count, but for what was being done this was the most strait forward, without doing double work.
      Now, you caught me. After many years hacking PHP, I have never ever needed to know the exact number of times the replacement succeeded. In the use cases I meet (and this applies to Perl as well), the task is always to do the replacement, if it can be done, and leave everything as it was otherwise.

      As of PHP 4, I can't really think of any straightforward solutions. Maybe, I would use a separate round of pattern matching first to derive the number, if I had to do such thing, but I am sure that other monks more familiar with this aspect of PHP will correct me, if I am wrong.


      Here's one way to do it in PHP. There are possibly better ways.

      #!/usr/bin/php -q <?php error_reporting(E_ALL); $data = array("one", "foo", "two", "foo", "three", "foo", "four", "foo", "foo"); $changed = 0; $new = preg_replace_callback("/foo/", create_function( '', '$GLOBALS{"changed"}++; return "bar";' ), $data); print_r($new); print "We changed $changed items\n"; ?>

      This prints

      Array ( [0] => one [1] => bar [2] => two [3] => bar [4] => three [5] => bar [6] => four [7] => bar [8] => bar ) We changed 5 items

      I hope this helps satisfy your curiosity

Re^2: Stupid mistakes I repeatedly make
by legato (Monk) on Mar 28, 2005 at 18:48 UTC

    This one, I managed to avoid. I did it once early in my Perl life, and learned the mantra before the bad habit set in:

    s/something/else/ for @list;

    But, how do you accomplish the same thing with map, and does it make any difference?

    Anima Legato
    .oO all things connect through the motion of the mind

      s/something/else/ for @list;

      But, how do you accomplish the same thing with map, and does it make any difference?

      my @new_list = map { ( my $tmp = $_) =~ s/.../.../; $tmp  } @list;

      It's useful only for those times when you don't want to corrupt the original list, for whatever reason

      You could probably also do:

      @list = map { s/.../.../; $_ } @list;

      but you'd take a performance hit for building the list in memory, I would think. (I haven't benchmarked it).

      Update: Anonymous makes a good point -- faster not to assign it back to itself. (but there is still a performance hit as compared to for/foreach, so just use one of those, and only use map if you don't want to corrupt the original).

        If you just want to modify the list:
        map {s/.../.../} @list;
        and in modern Perls, that won't build a list in memory.

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2021-04-20 08:37 GMT
Find Nodes?
    Voting Booth?

    No recent polls found