Find and replace keyword in a string with PHP - php

I have this code to find and replace some string if it's between some {{ and }}.
$string = 'This is my {{important keyword}}.';
$string = preg_replace('/{{(.*?)}}/', '$1', $string);
return $string;
How I can change the $1 part to have something like this:
important keyword
So the href needs to have the match item converted like a slug (words separated with a dash, no accent or special char).
Thanks.

You have to use preg_replace_callback() to allow change on matches in a function.
See also use($url) to allow the function to access to the external variable.
Code:
$url = 'https://example.com';
$string = 'This is my {{important keyword}}.';
$string = preg_replace_callback('/{{(.*?)}}/', function($matches) use ($url) {
$newURL = $url . '/' . str_replace(' ', '-', $matches[1]);
return '' . htmlentities($matches[1]) . '';
}, $string);
echo $string;
Output:
This is my important keyword.

Related

How can I avoid adding href to an overlapping keyword in string?

Using the following code:
$text = "أطلقت غوغل النسخة المخصصة للأجهزة الذكية العاملة بنظام أندرويد من الإصدار “25″ لمتصفحها الشهير كروم.ولم تحدث غوغل تطبيق كروم للأجهزة العاملة بأندرويد منذ شهر تشرين الثاني العام الماضي، وهو المتصفح الذي يستخدمه نسبة 2.02% من أصحاب الأجهزة الذكية حسب دراسة سابقة. ";
$tags = "غوغل, غوغل النسخة, كروم";
$tags = explode(",", $tags);
foreach($tags as $k=>$v) {
$text = preg_replace("/\b{$v}\b/u","$0",$text, 1);
}
echo $text;
Will give the following result:
I love PHP">love PHP</a>, but I am facing a problem
Note that my text is in Arabic.
The way is to do all in one pass. The idea is to build a pattern with an alternation of tags. To make this way work, you must before sort the tags because the regex engine will stop at the first alternative that succeeds (otherwise 'love' will always match even if it is followed by 'php' and 'love php' will never be matched).
To limit the replacement to the first occurence of each word you can remove tag from the array once it has been found and you test if it is always present in the array inside the replacement callback function:
$text = 'I love PHP, I love love but I am facing a problem';
$tagsCSV = 'love, love php, facing';
$tags = explode(', ', $tagsCSV);
rsort($tags);
$tags = array_map('preg_quote', $tags);
$pattern = '/\b(?:' . implode('|', $tags) . ')\b/iu';
$text = preg_replace_callback($pattern, function ($m) use (&$tags) {
$mLC = mb_strtolower($m[0], 'UTF-8');
if (false === $key = array_search($mLC, $tags))
return $m[0];
unset($tags[$key]);
return '<a href="index.php?s=news&tag=' . rawurlencode($mLC)
. '">' . $m[0] . '</a>';
}, $text);
Note: when you build an url you must encode special characters, this is the reason why I use preg_replace_callback instead of preg_replace to be able to use rawurlencode.
If you have to deal with an utf8 encoded string, you need to add the u modifier to the pattern and you need to replace strtolower with mb_strtolower)
the preg_split way
$tags = explode(', ', $tagsCSV);
rsort($tags);
$tags = array_map('preg_quote', $tags);
$pattern = '/\b(' . implode('|', $tags) . ')\b/iu';
$items = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$itemsLength = count($items);
$i = 1;
while ($i<$itemsLength && count($tags)) {
if (false !== $key = array_search(mb_strtolower($items[$i], 'UTF-8'), $tags)) {
$items[$i] = '<a href="index.php?s=news&tag=' . rawurlencode($tags[$key])
. '">' . $items[$i] . '</a>';
unset($tags[$key]);
}
$i+=2;
}
$result = implode('', $items);
Instead of calling preg_replace multiple times, call it a single time with a regexp that matches any of the tags:
$tags = explode(",", tags);
$tags_re = '/\b(' . implode('|', $tags) . ')\b/u';
$text = preg_replace($tags_re, '$0', $text, 1);
This turns the list of tags into the regexp /\b(love|love php|facing)\b/u. x|y in a regexp means to match either x or y.

replace URLs but not images using a regular expression

I have a string like this:
$str = ':-:casperon.png:-: google.com www.yahoo.com :-:sample.jpg:-: http://stackoverflow.com';
and I need to replace urls from the $str, but not images like casperon.png.
I have tried the following regex for replacing urls.
$regex = '/((http|ftp|https):\/\/)?[\w-]+(\.[\w-]+)+([\w.,#?^=%&:\/~+#-]*[\w#?^=%&\/~+#-])?/';
$str = preg_replace_callback( $regex, 'replace_url', $str);
and the php function like below.
function replace_url($m){
$link = $name = $m[0];
if ( empty( $m[1] ) ) {
$link = "http://".$link;
}
return ''.$name.'';
}
But it replaced the image as links. But I need the image as normal.Only the urls need to replace. So I put the images in between :-:image:-: the symbols. Can anyone help me..?
You can use this regex:
:-:.*?:-:\W*(*SKIP)(*F)|(?:(?:http|ftp|https)://)?[\w-]+(?:\.[\w-]+)+([\w.,#?^=%&:/~+#-]*[\w#?^=%&\/~+#-])?
RegEx Demo
This regex works on the concept of first selecting the unwanted text betweem :-: and :-: and discarding it using (*SKIP)(*F) directives.
You can change your code like that, using filter_var to check the possible urls:
function replace_url($m){
$link = (empty($m[1])) ? 'http://' . $m[0] : $m[0];
if (!filter_var($link, FILTER_VALIDATE_URL))
return $m[0];
return '' . $m[0] . '';
}
$regex = '~((?:https?|ftp)://)?[\w-]+(?>\.[\w-]+)+(?>[.,]*(?>[\w#?^=%/\~+#;-]+|&(?:amp;)?)+)*~';
$str = preg_replace_callback( $regex, 'replace_url', $str);

Strip single ended tags from string (img, hr, etc)

function stripSingleEndedTag($content, $allowed = array()){
(array)$allowed;
$singletags = array('<meta>','<img>','<input>','<hr>','<br>','<link>','<isindex>','<base>','<meta>','<nextid>','<bork>');
$stripthese = arrayfilterout ($singletags, $allowed);
$stripthese = str_replace(array('<','>'),'',$stripthese);
$pattern = '/<('. implode('|', $stripthese) .')[^>]+\>/i';
$content = preg_replace($pattern, "", $content);
return $content;
}
What I've got here will strip out a single ended tag like <bork /> but only if there is some character after 'bork' and before '>'. <bork > and <bork/> are stripped, but not <bork>
BTW, cant use strip_tags().
You can use:
$pattern = '/\<('. implode('|', $stripthese) .')[^>]*\>/i';
Original Answer:
Do you want to get rid of <bork /> and <bork/>, but not <bork> and <bork >?
It looks like what you want is:
$pattern = '/<('. implode('|', $stripthese) .').*\\\>/i';
Update: fix for greedy match:
$pattern = '/<('. implode('|', $stripthese) .').*?\\\>/i';
$pattern = '/<('. implode('|', $stripthese) .')[^>]*\\\>/i';

str_replace not replacing correctly

I have the following, simple code:
$text = str_replace($f,''.$u.'',$text);
where $f is a URL, like http://google.ca, and $u is the name of the URL (my function names it 'Google').
My problem is, is if I give my function a string like
http://google.ca http://google.ca
it returns
Google" target="_blank">Google</a> Google" target="_blank">Google</a>
Which obviously isn't what I want. I want my function to echo out two separate, clickable links. But str_replace is replacing the first occurrence (it's in a loop to loop through all the found URLs), and that first occurrence has already been replaced.
How can I tell str_replace to ignore that specific one, and move onto the next? The string given is user input, so I can't just give it a static offset or anything with substr, which I have tried.
Thank you!
One way, though it's a bit of a kludge: you can use a temporary marker that (hopefully) won't appear in the string:
$text = str_replace ($f, '' . $u . '',
$text);
That way, the first substitution won't be found again. Then at the end (after you've processed the entire line), simply change the markers back:
$text = str_replace ('XYZZYPLUGH', $f, $text);
Why not pass your function an array of URLs, instead?
function makeLinks(array $urls) {
$links = array();
foreach ($urls as $url) {
list($desc, $href) = $url;
// If $href is based on user input, watch out for "javascript: foo;" and other XSS attacks here.
$links[] = '<a href="' . htmlentities($href) . '" target="_blank">'
. htmlentities($desc)
. '</a>';
}
return $links; // or implode('', $links) if you want a string instead
}
$urls = array(
array('Google', 'http://google.ca'),
array('Google', 'http://google.ca')
);
var_dump(makeLinks($urls));
If i understand your problem correctly, you can just use the function sprintf. I think something like this should work:
function urlize($name, $url)
{
// Make sure the url is formatted ok
if (!filter_var($url, FILTER_VALIDATE_URL))
return '';
$name = htmlspecialchars($name, ENT_QUOTES);
$url = htmlspecialchars($url, ENT_QUOTES);
return sprintf('%s', $url, $name);
}
echo urlize('my name', 'http://www.domain.com');
// my name
I havent test it though.
I suggest you to use preg_replace instead of str_replace here like this code:
$f = 'http://google.ca';
$u = 'Google';
$text='http://google.ca http://google.ca';
$regex = '~(?<!<a href=")' . preg_quote($f) . '~'; // negative lookbehind
$text = preg_replace($regex, ''.$u.'', $text);
echo $text . "\n";
$text = preg_replace($regex, ''.$u.'', $text);
echo $text . "\n";
OUTPUT:
Google Google
Google Google

Replacing parameter values in URLs

// Below are a number of strings which need ammending
$string = "www.development_test.php?action=show_development_crs&test1&test2";
$string = "www.development_test.php?action=show_rfw&test1";
$string = "www.development_test.php?action=show_development_crs";
I need to write a preg_replace() function which replace the value between "=" + "&" or in the case of the bottom string everything after "=" when & doesnt exist with "newAction"..
Does anyone have any ideas?
This is what I have tried so far, but failed:
public function test1()
{
$action = "newAction";
$string = "www.development_crs.php?action=show_development_crs&test1&test2";
$pattern = '/(action=)(.*)(&)/';
$replacement = "action=$action&";
$string = preg_replace($pattern, $replacement, $string);
echo $string;
}
$action = 'newAction';
$string = 'www.development_crs.php?action=show_development_crs&test1&test2';
$pattern = '/action=[^&]+(.*)/';
$replacement = "action=$action$1";
$string = preg_replace($pattern, $replacement, $string);
echo $string;
Output:
www.development_crs.php?action=newAction&test1&test2
try the pattern below
$pattern='/action=([a-z0-9_\-%]+)&/';
$pattern = '/action=.*?(&|$)/';
$replacement = "action=$action$1";
I can see a few problems with your pattern. Not that I'm a regex expert however,
Try something like this:
/action=[^&]+/
or
/action=[^&]*/
This will match 'action=' and then the rest of the string until it encounters a &. The + means that it must have at least one character between the = and the & to accept the string.
Hope this helps :)

Categories