Jump to content

Recommended Posts

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 by Twitch

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 by mac_gyver

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 by Psycho

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.

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!

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.

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 by Psycho

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 by Twitch
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.