I know this question has more of a WordPress background to it, but I'm hoping it's just my lack of PHP knowledge that is the problem here.
I have a regex that looks for <a> tags such as: Find Out More, which are generated from content inputted by the user. Once it finds this content a foreach loop runs over the matched text and uses a WordPress function $postId = url_to_postid( $url ); to convert the URL into a PostID.
This is an example output: Find Out More.
This works fine as long as there is one link in each piece of matched text. However if there are two or more links, it sets every link to have the same href which is incorrect.
I'm sure this is something to do with how I've got my loop running. The code I'm using is below:
<?php
$string = get_field('sample_text_box');
$pattern = "/(?<=href=(\"|'))[^\"']+(?=(\"|'))/";
preg_match_all($pattern, $string, $matches);
$urls = $matches[0];
foreach($urls as $key => $url) {
$postId[$key] = url_to_postid( $url );
}
$newstring = preg_replace($pattern , $postId[$key] , $string);
echo $newstring;
?>
The line get_field('sample_text_box'); is an Advanced Custom Field function which "returns the value of the specified field". You can read about it here if it helps: https://www.advancedcustomfields.com/resources/get_field/
Thanks!
The problem with your code is that you are indeed replacing the pattern with a single value of $postId[$key], where $key is the last value assigned in foreach.
You also can not pass $postId instead because preg_replace expects both pattern and replacement be of the same type - whether strings, or arrays.
However, the problem is easily solved with preg_replace_callback function:
$pattern = '/(?<=href\="|\')([^"\']+)(?="|\')/m';
$new_string = preg_replace_callback($pattern, function ($matches) {
return isset($matches[1]) ? url_to_postid($matches[1]) : $matches[0];
}, $string);
Related
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 ;
I need some special filtering to certain text all over my website, like below:
function special_text( $content ) {
$search_for = 'specialtext';
$replace_with = '<span class="special-text"><strong>special</strong>text</span>';
return str_replace( $search_for, $replace_with, $content );
}
add_filter('the_content', 'special_text', 99);
It's doing thing in an excellent way, BUT...
in content if there's any link like: <a title="specialtext" href="http://specialtext.com">specialtext</a> then the title and href texts also changed and the link becomes broken.
How can I make exception there?
Is there a way I can put some exceptions in an array and str_replace() simply skip 'em?
You should use regular expression and use function preg_replace() to replace matched string. Here is the full implementation of your special_text() function.
function special_text( $content ) {
$search_for = 'specialtext';
$replace_with = '<span class="special-text"><strong>special</strong>text</span>';
return preg_replace( '/<a.*?>(*SKIP)(*F)|'.$search_for.'/m', $replace_with, $content );
}
In the following regular expression first, using <a.*?> - everything between <a...> is matched and using (*SKIP)(*F)| it is skipped and then from anything else $search_for is matched (in your case it's specialtext).
Jezzabeanz quite got it except you can simplify it still with:
return preg_replace("/^def/", $replace_with, $content);
If you just want to change the text between the the a tags then a regular expression works wonders.
Here is something I used when I was pulling data from emails sent to me:
(?<=">)(.*?\w)(?=<\/a)
returns "specialtext"
It also returns "specialtext test" if there is whitespace.
Regular expressions are definitely the way to go.
$subject = "abcdef";
$pattern = '/^def/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
?>
Source
And then do a replace on the returned matches.
I'm working on a bb-code replacement function when a user wants to post a smiley.
The problem is, that if someone uses a bb-code smiley that doesn't exists, it results in an empty post because the browser will not display the (non-existing) emoticon.
Here's my code so far:
// DO [:smiley:]
$convert_smiley = preg_match_all('/\[:(.*?):\]/i', $string, $matches);
if( $convert_smiley )
{
$string = preg_replace('/\[:(.*?):\]/i', "<i class='icon-smiley-$1'></i>", $string, $convert_smiley);
}
return $string;
The bb-code for a smiley usually looks like [:smile:] or like [:sad:] or like [:happy:] and so on.
The code above is working well, until someone post a bb-code that doesn't exists, so what I am asking for is a fix for non existing smileys.
Is there a possibility, in example to create an array, like array('smile', 'sad', 'happy') and only bb-code that matches one or more in this array will be converted?
So, after the fix, posting [:test:] or just [::] should not be converted and should be posted as original text while [:happy:] will be converted.
Any ideas? Thanks!
I put your possible smiley’s in non-grouping parentheses with or symbol in a regexp:
<?php
$string = 'looks like [:smile:] or like [:sad:] or like [:happy:] [:bad-smiley:]';
$string = preg_replace('/\[:((?:smile)|(?:sad)|(?:happy)):\]/i', "<i class='icon-smiley-$1'></i>", $string);
print $string;
Output:
looks like <i class='icon-smiley-smile'></i> or like <i class='icon-smiley-sad'></i> or like <i class='icon-smiley-happy'></i> [:bad-smiley:]
[:bad-smiley:] is ignored.
A simple workaround:
$string ="[:clap:]";
$convert_smiley = preg_match_all('/\[:(.*?):\]/i', $string, $matches);
$emoticons = array("smile","clap","sad"); //array of supported smileys
if(in_array($matches[1][0],$emoticons)){
//smily exists
$string = preg_replace('/\[:(.*?):\]/i', "<i class='icon-smiley-$1'></i>", $string, $convert_smiley);
}
else{
//smily doesn't exist
}
Well, the first issue is you are setting $convert_smiley to the true/false value of the preg_match_all() instead of parsing the results. Here is how I reworked your code:
// Test strings.
$string = ' [:happy:] [:frown:] [:smile:] [:foobar:]';
// Set a list of valid smileys.
$valid_smileys = array('smile', 'sad', 'happy');
// Do a `preg_match_all` against the smiley’s
preg_match_all('/\[:(.*?):\]/i', $string, $matches);
// Check if there are matches.
if (count($matches) > 0) {
// Loop through the results
foreach ($matches[1] as $smiley_value) {
// Validate them against the valid smiley list.
$pattern = $replacement = '';
if (in_array($smiley_value, $valid_smileys)) {
$pattern = sprintf('/\[:%s:\]/i', $smiley_value);
$replacement = sprintf("<i class='icon-smiley-%s'></i>", $smiley_value);
$string = preg_replace($pattern, $replacement, $string);
}
}
}
echo 'Test Output:';
echo htmlentities($string);
Just note that I chose to use sprintf() for the formatting of content & set $pattern and $replacement as variables. I also chose to use htmlentities() so the HTML DOM elements can easily be read for debugging.
This question has been asked multiple times, but I didn't find a working solution for my needs.
I've created a function to check for the URLs on the output of the Google Ajax API:
https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=site%3Awww.bierdopje.com%2Fusers%2F+%22Gebruikersprofiel+van+%22+Stevo
I want to exclude the word "profile" from the output. So that if the string contains that word, skip the whole string.
This is the function I've created so far:
function getUrls($data)
{
$regex = '/https?\:\/\/www.bierdopje.com[^\" ]+/i';
preg_match_all($regex, $data, $matches);
return ($matches[0]);
}
$urls = getUrls($data);
$filteredurls = array_unique($urls);
I've created a sample to make clear what I mean exactly:
http://rubular.com/r/1U9YfxdQoU
In the sample you can see 4 strings selected from which I only need the upper 2 strings.
How can I accomplish this?
function getUrls($data)
{
$regex = '#"(https?://www\\.bierdopje\\.com[^"]*+(?<!/profile))"#';
return preg_match_all($regex, $data, $matches) ?
array_unique($matches[1]) : array();
}
$urls = getUrls($data);
Result: http://ideone.com/dblvpA
vs json_decode: http://ideone.com/O8ZixJ
But generally you should use json_decode.
Don't use regular expressions to parse JSON data. What you want to do is parse the JSON and loop over it to find the correct matching elements.
Sample code:
$input = file_get_contents('https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=site%3Awww.bierdopje.com%2Fusers%2F+%22Gebruikersprofiel+van+%22+Stevo');
$parsed = json_decode($input);
$cnt = 0;
foreach($parsed->responseData->results as $response)
{
// Skip strings with 'profile' in there
if(strpos($response->url, 'profile') !== false)
continue;
echo "Result ".++$cnt."\n\n";
echo 'URL: '.$response->url."\n";
echo 'Shown: '.$response->visibleUrl."\n";
echo 'Cache: '.$response->cacheUrl."\n\n\n";
}
Sample on CodePad (since it doesn't support loading external files the string is inlined there)
I would like to create hyperlinks to the words in a paragraph.
For instance if the "Jim Carrey" name is in the array matches the word in string, then the Jim Carrey name should be in Hyperlink of "www.domian.net/name(Jim Carrey)" .
If the "mask" word in the array matches the word in string then it should be replace with corresponding url like "www.domian.net/mask"
<?php
$string="Jim Carrey found the new Mask";
$array=array("Jim Carrey","mask");
echo preg_replace( '/\b('.implode( '|', $array ).')\b/i', '$1', $string );
?>
You seem to have the right idea about how to put a link around the chosen text, but you seem to have not even tried to put in an href. Which is a shame, since it's as simple as typing in the URL with whatever parameter you want.
However, it does get a little complicated because you don't want the same thing both times (you want the literal word in one, but you want name(WORD) in the other). You could try this:
$array = array("Jim Carrey"=>"name(Jim Carrey)","mask"=>"mask");
echo preg_replace_callback("/\b".implode("|",array_keys($array))."\b/i",
function($m) use ($array) {
return "".$m."";
},$string);
<?php
$string="Jim Carrey found the new Mask";
$arr=array("Jim Carrey","Mask");
foreach($arr as $val)
$string = str_replace($val, '' . $val . '', $string);
echo $string;
?>