PHP keyword replacement using preg_replace and a FOR loop - php

I'm completely lost on what's wrong here. Any help will be appreciated.
I'm making a keyword replacement tool for a wordpress site. My problem is that my preg_replace seems to only run on the last element in the array when going through the post content.
The two get_options below are just textarea fields with each keyword and replacement on a separate line using character returns.
function keyword_replace($where) {
$keywords_to_replace = get_option('keywords_to_replace');
$keyword_links = get_option('keyword_links');
$KWs = explode("\n", $keywords_to_replace);
$URLs = explode("\n", $keyword_links);
$pattern = array();
$replacement = array();
for($i=0; $i< count($KWs); $i++) {
$pattern2 = '/<a[^>]*>(.*?)'.$KWs[$i].'(.*?)</a>/';
if(preg_match($pattern2, $where)) {
continue;
} else {
$pattern[$i] = '\'(?!((<.*?)|(<a.*?)))(\b'. $KWs[$i] . '\b)(?!(([^<>]*?)>)|([^>]*?</a>))\'si';
$replacement[$i] .= ''.$KWs[$i].'';
}
}
return preg_replace($pattern, $replacement, $where, -1);
}
add_filter('the_content','keyword_replace');
A var_dump() returns all the correct information, and nothing appears to be skipped in the dump. I'm stuck trying to figure out why it doesn't loop through the whole array.
Thanks for your help,
Rafael

I had a friend fix this for me. Just in case anyone else comes across a problem similar to mine, the fix was to use the trim() command around $KWs[$i] inside $pattern[$i].
$pattern[$i] = '\'(?!((<.*?)|(<a.*?)))(\b'. trim($KWs[$i]) . '\b)(?!(([^<>]*?)>)|([^>]*?</a>))\'si';
It all came down to windows vs. mac on character returns.

Related

Php find and replace words in a text from database tables

I'm working on a project. It searches and replaces words from the database in a given text. In the database a have 10k words and replacements. So ı want to search for each word and replace this word's replacement word.
By the way, I'm using laravel. I need only replacement ideas.
I have tried some ways but it replaces only one word.
My database table structure like below;
id word replacement
1 test testing
etc
The text is coming from the input and after the replacement, I wanna show which words are replaced in a different bg color in the result page.
I tried below codes working fine but it only replaces one word.
$article = trim(strip_tags($request->article));
$clean = preg_split('/[\s]+/', $article);
$word_count = count($clean);
$words_from_database_for_search = Words::all();
foreach($words_from_database_for_search as $word){
$content = str_replace($word['word'],
"<span class=\"badge badge-success\">$word[replacement]
</span>",
$article);
}
$new_content = $content ;
$new_content_clean = preg_split('/[\s]+/', $new_content);
$new_content_word_count= count($new_content_clean);
Edit,
Im using preg_replace instead of str_replace. I get it worked but this time i wanna show how many words changed so i tried to find the number of changed words from the text after replacement. It counts wrong.
Example if there is 6 changes it show 3 or 4
It can be done via preg_replace_callback but i didnt use it before so i dont know how to figure out;
My working codes are below;
$old_article = trim(strip_tags($request->article));
$old_article_word_count = count($old_article );
$words_from_database_array= Words::all();
$article_will_replace = trim(strip_tags($request->article));
$count_the_replaced_words = 0;
foreach($words_from_database_array as $word){
$article_will_replace = preg_replace('/[^a-zA-
ZğüşıöçĞÜŞİÖÇ]\b'.$word['word'].'\b\s/u',
" <b>".$word['spin']."</b> ",
$article_will_replace );
$count_the_replaced_words = preg_match_all('/[^a-zA-
ZğüşıöçĞÜŞİÖÇ]\b'.strip_tags($word['spin']).'\b\s/u',$article_will_replace
);
if($count_the_replaced_words ){
$count_the_replaced_words ++;
}
}
As others have suggested in comments, it seems your value of $content is being overwritten on each run of the foreach loop, with older iterations being ignored. That's because the third argument of your str_replace is $article, the original, unmodified text. Only the last word, therefore, is showing up on the result.
The simplest way to fix this would be to declare $content before the foreach loop, and then make $content the third argument of the foreach loop so that it is continually replaced with a new word on each iteration, like so:
$content = $article;
foreach($words_from_database_for_search as $word){
$content = str_replace($word['word'],
"<span class=\"badge badge-success\">$word[replacement]</span>",
$content);
}
Im confused, don't you need the <?php ... ?> around the $word[replacement] ?
foreach($words_from_database_for_search as $word){
$content = str_replace($word['word'],
"<span class=\"badge badge-success\"><?PHP $word[replacement] ?>
</span>",
$article);
}
and then move this in to the for-loop and add a dot before the equal-sign:
$new_content .= $content ;

Remove quotes from string inside of array

I have a string that looks like this:
$string = '"excludeIF":["miniTrack","isTriangleHanger","tubeTrack","boxTrack"]';
I need to get rid of the " that are inside of the [] array so it looks like this:
$string = '"excludeIF":[miniTrack, tubeTrack, boxTrack]';
I was trying some regex but I kept getting rid of all of the quotes.
For this particular example:
$string = '"excludeIF":["miniTrack","isTriangleHanger","tubeTrack","boxTrack"]';
preg_match("/((?<=\[).*(?=\]))/", $string, $match);
$change = str_replace('"', "", $match[0]);
$result = preg_replace("/$match[0]/", $change, $string);
What this does is it gets the content inside the square brackets, removes the quotes, then replaces the original content with the cleaned content.
This may run into errors if you have the exact same string outside of square brackets later on, but it should be an easy fix if you understand what I've written.
Hope it helps.
PS. It would also help if you showed us what regexes you were trying, as you were, perhaps, on the right path but just had some misunderstandings.
So yeah I agree with the comment about the XY Problem, but I would still like to try help.
$string = '"excludeIF":["miniTrack","isTriangleHanger","tubeTrack","boxTrack"]';
You will now need to find the start and end positions of the string that you want edited. This can be done by the following:
$stringPosition1 = strpos($string,'[');
$stringPosition2 = strpos($string,']');
Now you have the correct positions you are able to do a substr() to find the exact string you want edited.
$str = substr($string,$stringPosition1,$stringPosition2);
From here you can do a simple str_replace()
$replacedString = str_replace('"','',$str);
$result = '"excludeIF":' . $replacedString;
It is an excellent idea to look at the PHP docs if you struggle to understand any of the above functions. I truly believe that you are only as good at coding as your knowledge of the language is. So please have a read of the following documents:
Str_pos: http://php.net/manual/en/function.strpos.php
Sub_str: http://php.net/manual/en/function.substr.php
Str_replace: http://php.net/manual/en/function.str-replace.php
test this code:
<?php
$string = '"excludeIF":["miniTrack","isTriangleHanger","tubeTrack","boxTrack"]';
$str_array = str_split($string);
$string_new = '';
$id = 0;
foreach ($str_array as $value) {
if($value == '[' || $id != 0){
$id = ($value != ']') ? 1 : 0;
$string_new .= ($value != "\"") ? $value : '' ;
} else {
$string_new .= $value;
}
}
echo $string_new;
//RESULT "excludeIF":[miniTrack,isTriangleHanger,tubeTrack,boxTrack]
?>
Good luck!
EDIT
<?php
$string = '"excludeIF":["miniTrack","isTriangleHanger","tubeTrack","boxTrack"]';
$part = str_replace("\"","",(strstr($string,'[')));
$string = substr($string,0,strpos($string,'[')).$part;
echo $string;
?>
Other possible solution.
Fun with code!

Advanced first and last sentence functions

I'm trying to retrieve the first and last sentences from database text entries.
The code I have works fine in this example:
$text = "He was doing ok so far, but this one had stumped him. He was a bit lost..."
The functions:
function first_sentence($content) {
$pos = strpos($content, '.');
if($pos === false) {
return $content;
}
else {
return substr($content, 0, $pos+1);
}
} // end function
// Get the last sentence
function last_sentence($content) {
$content = array_pop(array_filter(explode('.', $content), 'trim'));
return $content;
} // end function
The last sentence function takes into account any trailing...'s at the end of a sentence, but neither can cope with the following:
$text = "Dr. Know-all was a coding master, he knew everything and was reputed the world over. But the Dr. was in trouble..."
Result:
First sentence: Dr.
Last sentence: was in trouble
I need to modify the functions to take into account things like 'Dr.' and other such abbreviations if that's possible, so the last text variable would come out as:
First sentence: Dr. Know-all was a coding master, he knew everything and was reputed the world over
Last sentence: But the Dr. was in trouble
Can it be done? Any help much appreciated!
You can exclude some word by replacing them.
<?
function first_sentence($content) {
$pos = strpos($content, '.');
if($pos === false) {
return $content;
}
else {
return substr($content, 0, $pos+1);
}
} // end function
// Get the last sentence
function last_sentence($content) {
$content = array_pop(array_filter(explode('.', $content), 'trim'));
return $content;
} // end function
$text = "Dr. Know-all was a coding master, he knew everything and was reputed the world over. But the Dr. was in trouble...";
$tmp = str_replace("Dr.","Dr____",$text);
echo $tmm ."\n";
echo str_replace("Dr____","Dr.",first_sentence($tmp ))."\n";
echo str_replace("Dr____","Dr.",last_sentence($tmp ));
?>
WORKING CODE
Maybe you thought about that..
Can you make a function to encode/decode the $content before you search for the sentences;
function encode_content($content){
return $encoded_content = str_replace("Dr.", "Dr#;#", $content);
}
And after you retrieve the sentences, decode again:
function decode_content($content){
return $encoded_content = str_replace("Dr#;#", "Dr." , $content);
}
You can check your substr length, and return only if it is longer than 3 characters (point included). If it is less or equal, you can use a whitelist in order not to stumble upon words such as "No", "Me", "Us", "Oh"... Scrabble dictionaries should be able to help you there :)
Just to answer my own question after putting some new functions together given the answers so far
function encode_text($content){
$search = array("Dr.", "i.e.", "Mr.", "Mrs.", "Ms."); // put our potential problems in an array
$replace = array("Dr#;#", "i#e#", "Mr#;#", "Mrs#;#", "Ms#;#"); // make them good for first and last sentence functions
$encoded_content = str_replace($search, $replace, $content);
return $encoded_content;
} // end encode
Then we just swap the search and replace variables around to make our decode function. Now they can be used with the first and last sentence functions above, and it works a charm. Adding stuff to the arrays is simple, thinking of what's appropriate to add tho is less so :)
Cheers!

php how to make a if str_replace?

$str is some value in a foreach.
$str = str_replace('_name_','_title_',$str);
how to make a if str_replace?
I want do the thing if have a str_replace then echo $str, else not, jump the current foreach then to the next. Thanks.
There is a fourth parameter to str_replace() that is set to the number of replacements performed. If nothing was replaced, it's set to 0. Drop a reference variable there, and then check it in your if statement:
foreach ($str_array as $str) {
$str = str_replace('_name_', '_title_', $str, $count);
if ($count > 0) {
echo $str;
}
}
If you need to test whether a string is found within another string, you can like this.
<?php
if(strpos('_name_', $str) === false) {
//String '_name_' is not found
//Do nothing, or you could change this to do something
} else {
//String '_name_' found
//Replacing it with string '_title_'
$str = str_replace('_name_','_title_',$str);
}
?>
http://php.net/manual/en/function.strpos.php
However you shouldn't need to, for this example. If you run str_replace on a string that has nothing to replace, it won't find anything to replace, and will just move on without making any replacements or changes.
Good luck.
I know this is an old question, but it gives me a guideline to solve my own checking problem, so my solution was:
$contn = "<p>String</p><p></p>";
$contn = str_replace("<p></p>","",$contn,$value);
if ($value==0) {
$contn = nl2br($contn);
}
Works perfectly for me.
Hope this is useful to someone else.

Preg match question

I'm sure someone already asked this question, but after searching for more than 1 hour on google, I decided to ask my question here.
I want to itterate over an array excisting of different strings/texts.
These texts contain strings with both ##valuetoreplace## and #valuetoreplace#
I want to make to preg_matches:
$pattern = '/^#{1}+(\w+)+#{1}$/';
if(preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE))
{
// do something with the #values#
}
AND
$pattern = '/^#{2}+(\w+)+#{2}$/';
if(preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE))
{
//do something with the ##value##
}
This works great.
Now my only problem is as follows:
When i have a string like
$valueToMatch = 'proceding text #value#';
My preg_match cant find my value anymore (as i used a ^ and a $).
Question: how can i find the #value# and the ##value##, without having to worry if these words are in the middle of a (multi-line) value?
*In addition:
What i want is to find patterns and replace the #value# with a db value and a ##value## with a array value.
For example:
$thingsToReplace = 'Hello #firstname# #lastname#,
How nice you joined ##namewebsite##.';
should be
'Hello John Doe,
How nice you joined example.com.'
Try this: /##([^#]+)##/ and /#([^#]+)#/, in that order.
Maybe nice to know for other visitors how i did it:
foreach($personalizeThis as $key => $value)
{
//Replace ##values##
$patternIniData = '/#{2}+(\w+)#{2}/';
$return = 'website'; //testdata
$replacedIniData[$key] = preg_replace($patternIniData, $return, $value);
//Replace #values#
$pattern = '/#{1}+(\w+)#{1}/';
$return = 'ASD'; //testdata
$replacedDbData[$key] = preg_replace($pattern, $return, $replacedIniData[$key]);
}
return $replacedDbData;

Categories