Page 1 of 3 123 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2004
    Posts
    206
    Rep Power
    10

    Problem with string pattern replacement


    Hi,

    I'm trying to replace all instances of a HTML <span> tag with the class="eventname" with <strong> tags instead.

    Currently:
    <span class="eventname">Text here</span>

    Desired:
    <strong>Text here</strong>

    Any ideas how I'd do this using the preg match function in PHP?

    Thanks in advance!
  2. #2
  3. Sarcky
    Devshed Supreme Being (6500+ posts)

    Join Date
    Oct 2006
    Location
    Pennsylvania, USA
    Posts
    10,692
    Rep Power
    6351
    You can just do it with str_replace, the tags don't change.

    You won't be able to replace the correct closing tags, though. A better idea would be to simply change your CSS so that span class is bold.

    -Dan
    HEY! YOU! Read the New User Guide and Forum Rules

    "They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." -Benjamin Franklin

    "The greatest tragedy of this changing society is that people who never knew what it was like before will simply assume that this is the way things are supposed to be." -2600 Magazine, Fall 2002

    Think we're being rude? Maybe you asked a bad question or you're a Help Vampire. Trying to argue intelligently? Please read this.
  4. #3
  5. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by denhamd2
    Hi,

    I'm trying to replace all instances of a HTML <span> tag with the class="eventname" with <strong> tags instead.

    Currently:
    <span class="eventname">Text here</span>

    Desired:
    <strong>Text here</strong>

    Any ideas how I'd do this using the preg match function in PHP?

    Thanks in advance!
    Yea! I've been working on my regex-fu, thanks for the fun test case

    I was only able to figure out how to do this in 2 passes; the first pass for the <span>, the second for the </span>. But, it seems to work. Should be academic to wrap this into a re-usable function.

    PHP Code:
    $regex         "/(<(span)[^>]*>)/"
    $regex2     "/(<\/span>)/";
            
    $html         '<span class="eventname">Text here</span><div>this is some more stuff</div>'
    $replaced     preg_replace($regex"<strong>"$html); 
    $replaced     preg_replace($regex2"</strong>"$replaced); 
    echo 
    $replaced// <span/> tags have been swapped for <strong/> tags 
    I threw the <div/> in there to see if the $regex would ignore HTML that wasn't a <span/>. Seems to have worked.

    Lemme know what you think.
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  6. #4
  7. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    You won't be able to replace the correct closing tags, though.
    Do I get bonus points for proving ManiacDan wrong?
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  8. #5
  9. Sarcky
    Devshed Supreme Being (6500+ posts)

    Join Date
    Oct 2006
    Location
    Pennsylvania, USA
    Posts
    10,692
    Rep Power
    6351
    Well I assumed the full text would contain multiple <span> tags of multiple class types (which your regexp doesn't cover) and could possibly include nested <span> tags (which NO regexp can cover). A single regexp to replace <span class="eventname"> and the next occurring </span> tag would be:
    PHP Code:
    $html '<span class="eventname">Text here</span><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <span class="eventname">The problem lies right <span style="font-size: large;">here</span> because there are nested spans</span>'
    ;  
    //replace the </span> with something rare first, so we can do a proper negative lookahead
    $html str_replace("</span>"""$html);
    $html preg_replace("/<span[^>]+class=\"eventname\"[^>]*>([^]+)+/""<strong>\\1</strong>"$html);
    //and switch back to </span> for the rest:
    $html str_replace("""</span>"$html);
    die(
    "<pre>" htmlentities($html) . "</pre>"); 
    Outputs:
    Code:
    <strong>Text here</strong><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <strong>The problem lies right <span style="font-size: large;">here</strong> because there are nested spans</span>
    -Dan
    HEY! YOU! Read the New User Guide and Forum Rules

    "They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." -Benjamin Franklin

    "The greatest tragedy of this changing society is that people who never knew what it was like before will simply assume that this is the way things are supposed to be." -2600 Magazine, Fall 2002

    Think we're being rude? Maybe you asked a bad question or you're a Help Vampire. Trying to argue intelligently? Please read this.
  10. #6
  11. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220

    Check it


    Now it's reusable for any tag.

    PHP Code:
    /**
     * Simple function for replacing a specific <html/> tag with another <html/> tag. 
     * @param string $find
     * @param string $replace
     * @param string $subject
     * @return string $revised_html
     */
    function replaceTags($find$replace$subject) {
        
    $find_start_tag     "/(<(" $find ")[^>]*>)/";
        
    $find_end_tag         "/(<\/" $find ">)/";
        
    $replace_start_tag     "<" $replace ">"
        
    $replace_end_tag     "<" $replace "/>"
        
        
    $revised_html         preg_replace($find_start_tag$replace_start_tag$subject); 
        
    $revised_html         preg_replace($find_end_tag$replace_end_tag$revised_html); 
        
        return 
    $revised_html
    }

    // test our new replaceTags() function
    $subject         '<span class="eventname">Text here</span><div>this is some more stuff</div>'
    $find             "span"
    $replace         "strong"

    $replace         replaceTags($find$replace$subject);
    // success! 
    echo $replace
    Aw hell yes.
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  12. #7
  13. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    Well I assumed the full text would contain multiple <span> tags of multiple class types (which your regexp doesn't cover) and could possibly include nested <span> tags (which NO regexp can cover). A single regexp to replace <span class="eventname"> and the next occurring </span> tag would be:
    PHP Code:
    $html '<span class="eventname">Text here</span><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <span class="eventname">The problem lies right <span style="font-size: large;">here</span> because there are nested spans</span>'
    ;  
    //replace the </span> with something rare first, so we can do a proper negative lookahead
    $html str_replace("</span>"""$html);
    $html preg_replace("/<span[^>]+class=\"eventname\"[^>]*>([^]+)+/""<strong>\\1</strong>"$html);
    //and switch back to </span> for the rest:
    $html str_replace("""</span>"$html);
    die(
    "<pre>" htmlentities($html) . "</pre>"); 
    Outputs:
    Code:
    <strong>Text here</strong><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <strong>The problem lies right <span style="font-size: large;">here</strong> because there are nested spans</span>
    -Dan
    C'mon, no sense of humor?

    I'll check to see if I can get it to work for multiple <span/>s.
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  14. #8
  15. Sarcky
    Devshed Supreme Being (6500+ posts)

    Join Date
    Oct 2006
    Location
    Pennsylvania, USA
    Posts
    10,692
    Rep Power
    6351
    Originally Posted by His Grooviness
    C'mon, no sense of humor?

    I'll check to see if I can get it to work for multiple <span/>s.
    Always a sense of humor!

    You can't get a regexp to work with nested tags, because the only way to do that is to count how "deep" you are to begin with. The only want to replace nested things is by walking through the string one character at a time and recording your "depth" as you go. Boring and tedious, but possible. There's a post by me on here somewhere that does it.

    -Dan
    HEY! YOU! Read the New User Guide and Forum Rules

    "They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." -Benjamin Franklin

    "The greatest tragedy of this changing society is that people who never knew what it was like before will simply assume that this is the way things are supposed to be." -2600 Magazine, Fall 2002

    Think we're being rude? Maybe you asked a bad question or you're a Help Vampire. Trying to argue intelligently? Please read this.
  16. #9
  17. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    Well I assumed the full text would contain multiple <span> tags of multiple class types (which your regexp doesn't cover) and could possibly include nested <span> tags (which NO regexp can cover). A single regexp to replace <span class="eventname"> and the next occurring </span> tag would be:
    PHP Code:
    $html '<span class="eventname">Text here</span><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <span class="eventname">The problem lies right <span style="font-size: large;">here</span> because there are nested spans</span>'
    ;  
    //replace the </span> with something rare first, so we can do a proper negative lookahead
    $html str_replace("</span>"""$html);
    $html preg_replace("/<span[^>]+class=\"eventname\"[^>]*>([^]+)+/""<strong>\\1</strong>"$html);
    //and switch back to </span> for the rest:
    $html str_replace("""</span>"$html);
    die(
    "<pre>" htmlentities($html) . "</pre>"); 
    Outputs:
    Code:
    <strong>Text here</strong><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <strong>The problem lies right <span style="font-size: large;">here</strong> because there are nested spans</span>
    -Dan
    Dude, I don't know... the little function I posted works for multiple <span/>s w/in a block of HTML. Dig:
    PHP Code:
    /**
     * Simple function for replacing a specific <html/> tag with another <html/> tag. 
     * @param string $find
     * @param string $replace
     * @param string $subject
     * @return string $revised_html
     */
    function replaceTags($find$replace$subject) {
        
    $find_start_tag     "/(<(" $find ")[^>]*>)/";
        
    $find_end_tag         "/(<\/" $find ">)/";
        
    $replace_start_tag     "<" $replace ">"
        
    $replace_end_tag     "<" $replace "/>"
        
        
    $revised_html         preg_replace($find_start_tag$replace_start_tag$subject); 
        
    $revised_html         preg_replace($find_end_tag$replace_end_tag$revised_html); 
        
        return 
    $revised_html
    }

    // test our new replaceTags() function
    $subject         '<span class="eventname">Text here</span>' 
                        
    '<div>this is some more stuff</div>' 
                        
    '<span>another one!</span>' 
                        
    '<span class="SuckItTrebecSuckItLongSuckItHard">Ill take therapist for 800</span>' 
                        
    '<table><tr><td>wow it still works biznatch</td></tr></table>' 
                        
    '<span class="DrGrooveIsTheBomb">Droppin da funk worldwide</span>'
    $find             "span"
    $replace         "strong"

    $replace         replaceTags($find$replace$subject);
    // success! 
    echo $replace
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  18. #10
  19. Sarcky
    Devshed Supreme Being (6500+ posts)

    Join Date
    Oct 2006
    Location
    Pennsylvania, USA
    Posts
    10,692
    Rep Power
    6351
    Oh yeah, yours replaces all span tags, but the OP only wants "eventname" spans replaced, not ALL spans. That's where the problem comes in. Because </span> can close ANY span, you can't tell which </span> you need to change into a </strong> unless you count how deep you go. Check the output of my test for the issue on the last line. The first eventname span is replaced properly, the next span is left alone, then you get nested spans and everything is broken.

    -Dan
    HEY! YOU! Read the New User Guide and Forum Rules

    "They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." -Benjamin Franklin

    "The greatest tragedy of this changing society is that people who never knew what it was like before will simply assume that this is the way things are supposed to be." -2600 Magazine, Fall 2002

    Think we're being rude? Maybe you asked a bad question or you're a Help Vampire. Trying to argue intelligently? Please read this.
  20. #11
  21. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    Well I assumed the full text would contain multiple <span> tags of multiple class types (which your regexp doesn't cover) and could possibly include nested <span> tags (which NO regexp can cover). A single regexp to replace <span class="eventname"> and the next occurring </span> tag would be:
    PHP Code:
    $html '<span class="eventname">Text here</span><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <span class="eventname">The problem lies right <span style="font-size: large;">here</span> because there are nested spans</span>'
    ;  
    //replace the </span> with something rare first, so we can do a proper negative lookahead
    $html str_replace("</span>"""$html);
    $html preg_replace("/<span[^>]+class=\"eventname\"[^>]*>([^]+)+/""<strong>\\1</strong>"$html);
    //and switch back to </span> for the rest:
    $html str_replace("""</span>"$html);
    die(
    "<pre>" htmlentities($html) . "</pre>"); 
    Outputs:
    Code:
    <strong>Text here</strong><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <strong>The problem lies right <span style="font-size: large;">here</strong> because there are nested spans</span>
    -Dan
    I tried the HTML you posted w/ my little function. It slaughtered your test case and ended it with a fatality. Swap this out for $subject in the post w/ my function, and see for yerself.

    PHP Code:
    $ManiacDanHTML =  '<span class="eventname">Text here</span><div>this is some more stuff</div> 
    <span class="somethignElse">Do not replace me!  I am a span!</span>
    <span class="eventname">The problem lies right <span style="font-size: large;">here</span> because there are nested spans</span>'

    Works just fine.

    BRING IT. LOL (this is way too much fun)
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  22. #12
  23. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    Oh yeah, yours replaces all span tags, but the OP only wants "eventname" spans replaced, not ALL spans. That's where the problem comes in. Because </span> can close ANY span, you can't tell which </span> you need to change into a </strong> unless you count how deep you go. Check the output of my test for the issue on the last line. The first eventname span is replaced properly, the next span is left alone, then you get nested spans and everything is broken.

    -Dan
    Hmmmm... gimme a second.
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  24. #13
  25. Sarcky
    Devshed Supreme Being (6500+ posts)

    Join Date
    Oct 2006
    Location
    Pennsylvania, USA
    Posts
    10,692
    Rep Power
    6351
    You are reading and responding almost as fast as my browser can refresh this thread, it's nuts.

    Since you can't write a recursive regexp, char-by-char stepping is the only way to ensure the proper replacement of nested spans.

    The fact that nested spans are technically incorrect is ignored by most people with this problem.

    -Dan
    HEY! YOU! Read the New User Guide and Forum Rules

    "They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." -Benjamin Franklin

    "The greatest tragedy of this changing society is that people who never knew what it was like before will simply assume that this is the way things are supposed to be." -2600 Magazine, Fall 2002

    Think we're being rude? Maybe you asked a bad question or you're a Help Vampire. Trying to argue intelligently? Please read this.
  26. #14
  27. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    You are reading and responding almost as fast as my browser can refresh this thread, it's nuts.

    Since you can't write a recursive regexp, char-by-char stepping is the only way to ensure the proper replacement of nested spans.

    The fact that nested spans are technically incorrect is ignored by most people with this problem.

    -Dan
    Put this in your IDE and smoke it (seriously just having fun btw )

    PHP Code:
    /**
     * Simple function for replacing a specific <html/> tag with another <html/> tag. 
     * @param string $find
     * @param string $find_class - Optional <tag class="$find_class"></tag> for the function to locate for replacement. If
     *                     set, the function will only replace tags which contain the given $find_class
     * @param string $replace
     * @param string $subject
     * @return string $revised_html
     */
    function replaceTags($find$find_class ""$replace$subject) {
        
    $find_start_tag     = (empty($find_class)) ? 
                                
    "/(<(" $find ")[^>]*>)/" 
                                
    "/(<(" $find " class=\"" $find_class "\")[^>]*>)/";
        
    $find_end_tag         "/(<\/" $find ">)/";
        
    $replace_start_tag     "<" $replace ">"
        
    $replace_end_tag     "<" $replace "/>"
        
        
    $revised_html         preg_replace($find_start_tag$replace_start_tag$subject); 
        
    $revised_html         preg_replace($find_end_tag$replace_end_tag$revised_html); 
        
        return 
    $revised_html
    }

    // test our new replaceTags() function
    $subject         '<span class="eventname">Text here</span>' 
                        
    '<div>this is some more stuff</div>' 
                        
    '<span>another one!</span>' 
                        
    '<span class="SuckItTrebecSuckItLongSuckItHard">Ill take therapist for 800</span>' 
                        
    '<table><tr><td>wow it still works biznatch</td></tr></table>' 
                        
    '<span class="DrGrooveIsTheBomb">Droppin da funk worldwide</span>'
    $find             "span"
    $replace         "strong"

    $find_class     ""
    $doesItWork     replaceTags($find$find_class$replace$subject);  
    echo 
    $doesItWork

    $find_class     "eventname"
    $workWithClass     replaceTags($find$find_class$replace$subject); 
    echo 
    "<hr/>"
    echo 
    $workWithClass
    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
  28. #15
  29. Moderator Emeritus
    Devshed Supreme Being (6500+ posts)

    Join Date
    Feb 2002
    Location
    Austin, TX
    Posts
    7,183
    Rep Power
    2220
    Originally Posted by ManiacDan
    You are reading and responding almost as fast as my browser can refresh this thread, it's nuts.

    Since you can't write a recursive regexp, char-by-char stepping is the only way to ensure the proper replacement of nested spans.

    The fact that nested spans are technically incorrect is ignored by most people with this problem.

    -Dan
    The updated function that I posted works w/ your nested <span> test case; just tried it.

    Looks like recursive regex wasn't needed? Though, if it was, in theory you could write a recursive function that did a preg_match() each time it did a pass, and re-called itself if preg_match() came back with anything. I was worried about an infinite loop w/ that approach, though, since there was no way to reliable tell it when to call it quits. The function I wrote seems to work just fine w/ the nested <span> tag test case you posted; view source shows only the <span class="eventname" /> as being replaced w/ <strong/>, whereas all the other <span/>s were ignored.

    So... problem solved.

    DrGroove, Devshed Moderator | New to Devshed? Read the User Guide | Connect with me on LinkedIn
Page 1 of 3 123 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo