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

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

Hi. I was wondering if there is a capability in Perl to register a call back to the regex engine and call that registered function each time a particular match is made. For example, consider the string: "this is a string". I want to count the number of 's' in the string. Normally I would use a string utility and pop one character at a time and count the 's' as I come across them. I think a better way would be to make a regex that has a callback to a character class, \s\ in this case, and increments a global variable each time it matches an 's'.

Replies are listed 'Best First'.
Re: callback for regex engine
by LanX (Saint) on Jun 20, 2013 at 22:51 UTC
    Perl regexes allow to embed perlcode which is called during backtracking process.

    Something like /pattern(?{ code } )/g (see also (??{...})

    But in your simple case an iterator with while (/pattern/g) {code} is certainly better style (readability, maintainability, not an experimental feature!¹)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    PS: plz use code-tags

    update
    DB<123> $str = join "","a".."j" => "abcdefghij" DB<124> $x=0;$str =~ /(\w)(?{print "match ",++$x," $1 \n"})/g match 1 a match 2 b match 3 c match 4 d match 5 e match 6 f match 7 g match 8 h match 9 i match 10 j => ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j") DB<125> $x=0; while ( $str =~ /(\w)/g ) {print "match ",++$x," $1 \n +"} match 1 a match 2 b match 3 c match 4 d match 5 e match 6 f match 7 g match 8 h match 9 i match 10 j => ""

    ¹) perlre 5.10-5.16

    "(?{ code })" WARNING: This extended regular expression feature is considered experimental, and may be changed without n +otice. Code executed that has side effects may not perform identically from version to version due to the effect + of future optimisations in the regex engine.
Re: callback for regex engine
by kennethk (Abbot) on Jun 20, 2013 at 23:38 UTC
    LanX has a good answer. So, moving on and proselytizing, regular expressions give you enough power that if you feel like you need an internal callback, you are probably using them wrong. For the case of counting 's' in a string, the easiest answer is
    $count = $var =~ tr/s/s/;
    as documented in How can I count the number of occurrences of a substring within a string? in perlfaq4. I try to keep regular expressions short and sweet, and if I need really complex logic, I write that in Perl so that it's more than line noise to the casual observer.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: callback for regex engine
by zork42 (Monk) on Jun 21, 2013 at 09:26 UTC
    I was wondering if there is a capability in Perl to register a call back to the regex engine and call that registered function each time a particular match is made.
    This might be of interest:
    s///e and s///ee allow you to execute arbitrary any code (presumably including function calls) for each match
    See s/PATTERN/REPLACEMENT/msixpodualgcer in Regexp Quote Like Operators (you have to go down a few pages):
    e  Evaluate the right side as an expression.
    ee Evaluate the right side as a string then eval the result.


    UPDATE: s/arbitrary/any/
    (In response to ikegami's post below. Unless I'm misunderstanding ikegami's misunderstanding :) )
      [I was confused by the term "arbitrary code", which is normally used to refer to how s///ee can execute code found in data. Ignore this post.]