SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    masquerading Nick's Avatar
    Join Date
    Jun 2003
    Location
    East Coast
    Posts
    2,215
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    pattern matching & replacement

    It's been a long time since I have done any pattern matching, so I'm a little hazy on where to start. I'm trying to replace every instance of the string
    Code:
    [attachment:x]
    with the output of a function call
    Code:
    getAttachment(x)
    where 'x' is an integer. I've been playing around with preg_replace_callback. Right now I have this, but it won't even run:

    PHP Code:
    $text preg_replace_callback('|\[attachment:[0-9]+\]|'getAttachment($1), $body); 
    Nick . all that we see or seem, is but a dream within a dream
    Show someone you care, send them a virtual flower.
    Good deals on men's watches

  2. #2
    Web Professional
    Join Date
    Oct 2008
    Location
    London
    Posts
    862
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PHP Code:
    <?php
    function callback($match)
    {
        return 
    $match[1]; // $match[1] is the number
    }

    $text "hello [attachment:23] there";

    echo 
    preg_replace_callback("#\[attachment:(\d+)]#""callback"$text);

  3. #3
    masquerading Nick's Avatar
    Join Date
    Jun 2003
    Location
    East Coast
    Posts
    2,215
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This may be a novice question, but does the function have to be called 'callback'? How does the script know that the variable is stored in $match, since I don't see anything being passed into the second param of preg_replace_callback?
    Nick . all that we see or seem, is but a dream within a dream
    Show someone you care, send them a virtual flower.
    Good deals on men's watches

  4. #4
    SitePoint Enthusiast nrg_alpha's Avatar
    Join Date
    Dec 2008
    Posts
    81
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by decowski View Post
    PHP Code:
    <?php
    function callback($match)
    {
        return 
    $match[1]; // $match[1] is the number
    }

    $text "hello [attachment:23] there";

    echo 
    preg_replace_callback("#\[attachment:(\d+)]#""callback"$text);

    I just learned something from your pattern... I noticed that you failed to escape the final ] character in the pattern.. but the entire pattern works... I'm thinking to myself, why would it work? From how I see it, it contains a ] which you would think would make the regex engine think it is the closing square bracket of a character class, but since there is no opening character class bracket (as the intial [ is escaped and thus treated as a literal), I figured this would trip the regex engine.

    Interesting....

  5. #5
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There was never an unescaped [ to put the parser into "parse stuff in character class" mode. A ] only has special meaning when the parser is in that mode. Likewise, a [ character has no special meaning when the parser is in that mode, so this works.

    /[[]/

  6. #6
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    This thread may help you also Nick.
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  7. #7
    SitePoint Enthusiast nrg_alpha's Avatar
    Join Date
    Dec 2008
    Posts
    81
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by crmalibu View Post
    There was never an unescaped [ to put the parser into "parse stuff in character class" mode. A ] only has special meaning when the parser is in that mode. Likewise, a [ character has no special meaning when the parser is in that mode, so this works.

    /[[]/
    Yeah, I know that a pattern like that would work (which makes sense.. charcaters within the character class are usually treated differently (read, literally, as in this case... as we know, certain meta characters retain their special meaning within the character class, depending on their location of course) .

    I just figured since it runs into a closing unescaped ] (without a matching opening [), it would choke (my reasoning behind this is as follows)

    the above argument doesn't apply to ( and ) capturing parenthesis.

    For example;

    PHP Code:
    $str 'this is (really) only a test!';
    $str preg_replace('#\([^)]+)#'''$str);
    echo 
    $str// Warning: preg_replace() [function.preg-replace]: Compilation failed: unmatched parentheses at offset... 
    Since the last ) is not escaped, this trips up the regex system (unlike parsing using character class brackets). For that snippet to work, it would require the closing bracket to be escaped.. So based on this, I assumed the same would hold true for parsing in character classes as with captures and what have you.

    I chalk this up as learning something new.. new nuances of regex that I didn't know about previously. Live and learn... live and learn.

  8. #8
    masquerading Nick's Avatar
    Join Date
    Jun 2003
    Location
    East Coast
    Posts
    2,215
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have another question related to this. Inside my function that does all of my preg_replace_class, I take in a variable as a parameter. I would like to pass that variable along in my callback, along with the match data. How would I go about doing that?

    PHP Code:
    function process($someData$text)
    {
       
    $text preg_replace_callback("|\{attachment:(\d+)\}|""callback($someData)"$text);
       
    // etc
    }

    function 
    callback($someData$match)
    {
      
    // etc

    Nick . all that we see or seem, is but a dream within a dream
    Show someone you care, send them a virtual flower.
    Good deals on men's watches

  9. #9
    masquerading Nick's Avatar
    Join Date
    Jun 2003
    Location
    East Coast
    Posts
    2,215
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I keep getting this error:

    PHP Code:
    Requires argument 2'getAttachment'to be a valid callback 
    When my code looks like this:

    PHP Code:
    $text preg_replace_callback("|\{attachment:(\d+)\}|"'getAttachment'$text);

    [
    snip]

        function 
    getAttachment($matches)
        {            
            
    $text "Found attachment ID {$matches[0]}";
                
            return 
    $text;
        } 
    Can't get much simpler than that. What constitutes a valid callback function?
    Nick . all that we see or seem, is but a dream within a dream
    Show someone you care, send them a virtual flower.
    Good deals on men's watches

  10. #10
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Is this in an object Nick?
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  11. #11
    masquerading Nick's Avatar
    Join Date
    Jun 2003
    Location
    East Coast
    Posts
    2,215
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's inside an abstract class. I tried making the callback static but that didn't work.
    Nick . all that we see or seem, is but a dream within a dream
    Show someone you care, send them a virtual flower.
    Good deals on men's watches

  12. #12
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    If that's so, the callback parameter needs to be an array.
    PHP Code:
    preg_replace_callback($pattern, array('class''method'), $string
    Example:
    PHP Code:
    <?php
    class Money
    {
        public function 
    decimalise($number)
        {
            return 
    sprintf('%01.2f'array_shift($number));
        }
    }

    echo 
    preg_replace_callback(
        
    '~[0-9]+~i',
        array(
            
    'Money',
            
    'decimalise'
        
    ),
        
    'Price £100 pounds'
    );
    #Price £100.00 pounds
    ?>
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  13. #13
    masquerading Nick's Avatar
    Join Date
    Jun 2003
    Location
    East Coast
    Posts
    2,215
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh, ok, thanks. Is there anyway to pass in a custom variable (not the match array) to the callback from the function call? I need to pass in a mysql link reference. Something like...

    PHP Code:
    function callback($matches$sql) { .. } 
    Nick . all that we see or seem, is but a dream within a dream
    Show someone you care, send them a virtual flower.
    Good deals on men's watches

  14. #14
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, with php 5.3+ you can use a closure to easily solve this
    PHP Code:
    $callback = function($matches) use ($link) {
        return 
    stuff;

    Otherwise, next cleanest is to use an object so you can inject dependencies into its scope
    PHP Code:
    class Foo {
        protected 
    $dependancy;
        function 
    __construct($dependancy) {
            
    $this->dependancy $dependancy;
        }
        function 
    myCallback($matches) {
            
    //use $this->dependancy
            
    return stuff;
        }
    }

    $callback = array(new Foo($link), 'myCallback'); 
    A regular function + global variable/symbol can work in some situations, but it's ugly.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •