Twitch Posted May 22, 2014 Share Posted May 22, 2014 (edited) Hello All, I've been knocking my head against the wall for several hours trying to figure out what's going on with a simple string replace. For the most part it is working beautifully, but if a string contains a similar but not exact match it still replaces the non match. I was under the impression that str_replace always looks for an exact match. I have custom tags that are in strings of text that are structured like: [A_CUSTOM_HEADER] [A_CUSTOM_TITLE] and so on. They always start with "[A_CUSTOM" and end with a " ] ". In between the start and end can be just about anything. So my problem is if I have [A_CUSTOM] and [A_CUSTOM_TAG] in the same text str_replace seems to incorrectly replace all the [A_CUSTOM_TAG] with the [A_CUSTOM] content and the match never happens for the [A_CUSTOM_TAG] content. For example: $content = 'Here is some text and [A_CUSTOM]. Here is more text and [A_CUSTOM_TAG]'. $content = str_replace('[A_CUSTOM]','I have a and custom',$content); $content = str_replace('[A_CUSTOM_TAG]','I have a, custom and tag',$content); So running that code The [A_CUSTOM_TAG] content never gets replaced correctly, it is replaced on the first pass with the [A_CUSTOM] replacement content. I hope this make sense I'm trying to explain it the best I can. I tried using preg_replace() with \b to match the whole word but didn't get anything close to the respected results...haha I'm sure I'm missing something simple...or at least I hope I am. Thanks in advance! Edited May 22, 2014 by Twitch Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/ Share on other sites More sharing options...
mac_gyver Posted May 22, 2014 Share Posted May 22, 2014 (edited) your example, after fixing the php syntax error in the first line, does work. if your tags didn't have unique delimiters (at least the closing one) - [] around them, and were only the text - A_CUSTOM and A_CUSTOM_TAG, then the code would exhibit the symptom you describe. Edited May 22, 2014 by mac_gyver Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480461 Share on other sites More sharing options...
Twitch Posted May 22, 2014 Author Share Posted May 22, 2014 Thanks for the reply. Yea I had a missing single quote in my example code. That's a very simplistic example. I guess I'll have to look elsewhere in the code for the culprit. Thanks again for the reply. Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480464 Share on other sites More sharing options...
Psycho Posted May 22, 2014 Share Posted May 22, 2014 (edited) I don't see any issues either. Perhaps you are looking at a different file than the one that is actually being run or something else where the code you are looking at is not the code that is being executed (it's happened to all of us). Or, if you had a bug and fixed it, perhaps the page is showing the previous cached results. Anyway, once you find your problem, you can remove the multiple lines of code by utilizing arrays for the search and replacement values. If you have a lot of these it will be much easier to manage this way $replacements = array( '[A_CUSTOM]' => 'I have a and custom', '[A_CUSTOM_TAG]' => 'I have a, custom and tag' ); $content = 'Here is some text and [A_CUSTOM]. Here is more text and [A_CUSTOM_TAG]'. $content = str_replace(array_keys($replacements), $replacements, $content); Edited May 22, 2014 by Psycho Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480465 Share on other sites More sharing options...
mac_gyver Posted May 22, 2014 Share Posted May 22, 2014 if you are using notepad++ as your method of editing files, they recently introduced a feature that broke, by default, the whole purpose of editing files, i.e. to save the changes you made to the actual file when you exit the editor, but instead holds the changes in an editor session. what you see in the editor isn't what's in the file unless you explicitly save the file before you exit the editor or turn off this feature. Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480469 Share on other sites More sharing options...
Twitch Posted May 22, 2014 Author Share Posted May 22, 2014 (edited) Thanks for all the replies. mac_gyver I'm using Coda 2 on a Mac to edit files. It must be elsewhere in my code. I'll reply back if I find out what it was. Thanks again! Edited May 22, 2014 by Twitch Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480482 Share on other sites More sharing options...
Twitch Posted May 22, 2014 Author Share Posted May 22, 2014 I found the culprit. The code I posted earlier runs in a loop from an array of custom tags. It's the preg_match_all that's incorrectly matching. I should have known that was the likely place, but I've been up since 3 am and it's almost 3 pm my time now so my brain is not functioning properly. So here is what is going wrong: $custom_tag_array = array('A_CUSTOM','A_CUSTOM_TAG'); foreach($custom_tag_array as $tag){ $opening_pattern = '~\[A_'.$tag.'(.*?)\]~';//THIS APPEARS TO BE THE CULPRIT $closing_pattern = '[/A_'.$tag.']'; preg_match_all($opening_pattern, $content, $matches); if (!empty($matches[0])){ foreach($matches[0] as $match){ //THERE IS A FILE HERE THAT PROCESSES THE REPLACEMENT STRING BASED ON THE TAG $content = str_replace($match,$replacement_string,$content); }//foreach($matches[0] as $match){ }//foreach($custom_tag_array as $tag){ If I print_r($matches[0]); when the A_CUSTOM is in the loop it also shows that it matched A_CUSTOM_TAG. I need the A_'.$tag.' of the opening and closing patters to be more greedy. (.*?) part of the opening pattern is to catch the optional parameters. I tried some of the suggesting on a regex site, but I'm guessing I wasn't using them properly. Any suggestions on how to make the match more exact? Thanks in advance! Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480486 Share on other sites More sharing options...
Psycho Posted May 22, 2014 Share Posted May 22, 2014 That is very different from what you previously posted. I don't recall anything about opening and closing tags. Your example only showed a single placeholder tag that was being replaced. Plus, your closing patter has no delimiters. And, your code (as shown above) won't match anything. Your tags in the array already have "A_", but then you are appending another "A_" when creating the pattern. If you have opening and closing tags, then I'm really not sure what you are trying to accomplish. Are you trying to create your own BBCode type parser where the content between the tags will be modified? By only giving us partial and/or erroneous information we are going to waste our time. Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480490 Share on other sites More sharing options...
Psycho Posted May 22, 2014 Share Posted May 22, 2014 (edited) Here's an example of how you can extract the content between the two tags then replace it with modified content (which is what I think you are trying to do): $content = "This is content with [A_CUSTOM]bold[\A_CUSTOM] and [A_CUSTOM_TAG]italic[\A_CUSTOM_TAG] text"; $custom_tag_array = array( 'A_CUSTOM' => '<b>\\1</b>', 'A_CUSTOM_TAG' => '<i>\\1</i>' ); foreach($custom_tag_array as $tag => $replacement) { $pattern = "#\[{$tag}\](.*?)\[\\\\{$tag}\]#"; $content = preg_replace($pattern, $replacement, $content); } echo $content; Output This is content with <b>bold</b> and <i>italic</i> text Edited May 22, 2014 by Psycho Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480491 Share on other sites More sharing options...
Twitch Posted May 22, 2014 Author Share Posted May 22, 2014 (edited) Sorry I didn't mean to be vague I was just trying to give you the parts that I thought might be the issue as not to post a ton of code making the post very long. I thought less would make it easier to read. I really appreciate the replies and I definitely don't want to waste your time. I'll give more of a real example. Also I apologize for the typos and errors in earlier code. I was retyping code instead of cutting and pasting. I'm basically doing a simple template. I may not be going about it correctly but this way works with the exception of custom tags that start with the same text. I have used less compact code so you can see my workflow. For example: $custom_tag_array = array('A_ROW','A_COLUMN','A_COLUMN_HEADER'); $content = '[A_ROW] [A_COLUMN] [A_COLUMN|style^color:#00ff00]NESTED COLUMN LEFT<br />It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).[/A_COLUMN] [A_COLUMN]<span style="color:#0000ff;">NESTED COLUMN RIGHT<br />It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).</span>[/A_COLUMN] [/A_COLUMN] [A_COLUMN] Outer right half [/A_COLUMN] [/A_ROW]'; foreach($custom_tag_array as $tag){ $matches = array(); $opening_pattern = '~\['.$tag.'(.*?)\]~s'; $closing_pattern = '[/'.$tag.']'; preg_match_all($opening_pattern, $content, $matches); if (!empty($matches[0])){ foreach($matches[0] as $match){ $options_text = preg_replace($opening_pattern, '$1', $match); $options = explode('|',$options_text);//get the parameters - first pipe is for readability but not required foreach($options as $setting){ if (empty($setting)) continue; $setting_exp = explode('^', $setting); if (!isset($setting_exp[1])) continue; ${$setting_exp[0]} = $setting_exp[1];//make variable out of the option }//foreach($options as $setting){ if (!isset($class)){$class = '';} if (isset($style)){$style = 'style="'.$style.'"';}else{$style = '';} switch($tag){ case 'A_ROW': $replacement_string = '<div class="custom-row '.$class.'" '.$style.'>'; $closing_tag = '</div><!--/'.$tag.'-->'; break; case 'A_COLUMN': $replacement_string = '<div class="custom-column '.$class.'" '.$style.'>'; $closing_tag = '</div><!--/'.$tag.'-->'; break; case 'A_COLUMN_HEADER': $replacement_string = '<h1 class="custom-header '.$class.'" '.$style.'>'; $closing_tag = '</h1><!--/'.$tag.'-->'; break; }//switch($component){ $content = str_replace(array($closing_pattern,$match),array($closing_tag,$replacement_string),$content); }//foreach($matches[0] as $match){ }//if (!empty($matches[0])){ }//foreach($custom_tag_array as $tag){ echo $content; The above code works as expected. It generates the expected html <div class="custom-row "> <div class="custom-column " style=""> <div class="custom-column " style="color:#00ff00">NESTED COLUMN LEFT<br>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).</div><!--/A_COLUMN--> <div class="custom-column " style=""><span style="color:#0000ff;">NESTED COLUMN RIGHT<br>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).</span></div><!--/A_COLUMN--> </div><!--/A_COLUMN--> <div class="custom-column " style=""> Outer right half </div><!--/A_COLUMN--> </div> However if I place [A_COLUMN_HEADER]Header Text[/A_COLUMN_HEADER] in the content it renders the following <div class="custom-row "> <div class="custom-column " style=""> <div class="custom-column " style="style=" ""="">Header Text[/A_COLUMN_HEADER] <div class="custom-column " style="color:#00ff00">NESTED COLUMN LEFT<br>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).</div><!--/A_COLUMN--> <div class="custom-column " style=""><span style="color:#0000ff;">NESTED COLUMN RIGHT<br>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).</span></div><!--/A_COLUMN--> </div><!--/A_COLUMN--> <div class="custom-column " style=""> Outer right half </div><!--/A_COLUMN--> </div><!--/A_ROW--> </div> I believe the culprit is in my opening_pattern. It's matching A_COLUMN_HEADER when it is looping through the A_COLUMN. It works if I put A_COLUMN_HEADER first in the loop, but I was hoping for a better solution in the matching so it didn't matter which order they were in. Hopefully this makes it more clear. Also, I have used the method of matching both the opening and closing tags like you posted above, however that seemed to cause issues with nested tags. Course it could have been bad code on my part...haha Thanks again for all the help. Edited May 22, 2014 by Twitch Quote Link to comment https://forums.phpfreaks.com/topic/288681-simple-string-replace-not-matching-exactly/#findComment-1480512 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.