I have a string of HTML with tags inside saved in the database e.g:
<p>Hello {$name}, welcome to {$shop_name}....</p>
I want to replace all of the tags with real data, now at the moment I loop through all available data and replace if it exists.
foreach($data as $key => $data){
$content = str_replace('{$'.$key.'}', $data, $content);
}
Is there a better way of doing this without looping through all of the $data? This is now growing to over 5000 rows.
I mean is it possible to extract all variables {$name}/{$shop_name} then do a replace on only the found?
You can do it with a single str_replace call.
$find = array();
$replace = array();
foreach($data as $key => $data) {
$find[] = "\{$" . $key . "}";
$replace[] = $data;
}
$content = str_replace($find, $replace, $content);
Unless there is a real performance issue, I wouldn't worry about it too much.
str_replace accepts arrays, you can build the array with array_keys, array_values and user array_map to add the {$}
$content = str_replace(
array_map(function($e) { return '{$' . $e . '}';}, array_keys($data)),
array_values($data),
$content);
Can just do
$content = preg_replace('/\{$(\w+)\}/e', '$data[\'$1\']', $content);
Related
I am trying to create pdf from the values of a dynamic form.
I am collecting and storing dynamic inputs like this.
$inputarray = array();
foreach ($_POST['input'] as $input) {
$inputarray[] = $input;
}
Now I want to replace a template with the values collected from the form. My current codes look like this.
//count total number of inputs
$icount = count($_POST['input']);
//replace template with values
ob_start();
$require_once 'template.php';
$html = ob_get_clean();
$template = str_replace(array('%name%', '%input0%', '%input1%', '%input2%'), array($name, $inputarray[0], $inputarray[1], $inputarray[2]), $html);
The code of my template.php looks like this.
<tr><td>%name%</td></tr>
<?php
for ($i=0; $i<$icount; $i++){
echo '<tr>';
echo '<td>%input'.$i.'%</td>';
echo '</tr>';
?>
My code is working fine if I use %input1%, %input2% manually. My question is how do I automate that part?
P.S: I am still in beginning stage of learning and not proficient in object-oriented style. If possible, please explain in procedural style.
Edit: I don't understand why my question is closed. I would really like to know from someone that which part of my question is not understandable. English is not my first language and if some parts are not clear enough, at least I deserve specific feedback, not something general like "your question is not clear".
Something like this should work:
$search = array();
$search[] = '%name%';
$replace = array();
$replace[] = $name;
// make sure $_POST['input'] is zero-indexed, otherwise apply `array_values`
foreach ($_POST['input'] as $key => $input) {
$search[] = '%input' . $key . '%';
$replace[] = $input;
}
// next
$template = str_replace($search, $replace, $html);
You can also try this.
$template = '%input2% %input1% %input0% %name%';
$inputarray = [ 'another', "is", "This" ];
foreach ($inputarray as $key => $value) {
$replacement [ '%input'.$key.'%' ] = $value ;
}
$replacement[ "%name%" ] = 'example';
$template = strtr( $template, $replacement );
In my article, I want to automatically add links to keywords.
My keywords array:
$keywords = [
0=>['id'=>1,'slug'=>'getName','url'=>'https://example.com/1'],
1=>['id'=>2,'slug'=>'testName','url'=>'https://example.com/2'],
2=>['id'=>3,'slug'=>'ign','url'=>'https://example.com/3'],
];
This is my code:
private function keywords_replace(string $string, array $key_array)
{
$array_first = $key_array;
$array_last = [];
foreach ($array_first as $key=>$value)
{
$array_last[$key] = [$key, $value['slug'], '<a target="_blank" href="' . $value['url'] . '" title="' . $value['slug'] . '">' . $value['slug'] . '</a>'];
}
$count = count($array_last);
for ($i=0; $i<$count;$i++)
{
for ($j=$count-1;$j>$i;$j--)
{
if (strlen($array_last[$j][1]) > strlen($array_last[$j-1][1]))
{
$tmp = $array_last[$j];
$array_last[$j] = $array_last[$j-1];
$array_last[$j-1] = $tmp;
}
}
}
$keys = $array_last;
foreach ($keys as $key)
{
$string = str_ireplace($key[1],$key[0],$string);
}
foreach ($keys as $key)
{
$string = str_ireplace($key[0],$key[2],$string);
}
return $string;
}
result:
$str = "<p>Just a test: getName testName";
echo $this->keywords_replace($str,$keywords);
like this:Just a test: getName testName
very import: If the string has no spaces, it will not match.Because I will use other languages, sentences will not have spaces like English. Like Wordpress key words auto link
I think my code is not perfect,Is there a better algorithm to implement this function? Thanks!
You can use array_reduce and preg_replace to replace all occurrences of the slug words in your string with the corresponding url values:
$keywords = [
0=>['id'=>1,'slug'=>'getName','url'=>'https://www.getname.com'],
1=>['id'=>2,'slug'=>'testName','url'=>'https://www.testname.com'],
2=>['id'=>3,'slug'=>'ign','url'=>'https://www.ign.com'],
];
$str = "<p>Just a test: getName testName";
echo array_reduce($keywords, function ($c, $v) { return preg_replace('/\\b(' . $v['slug'] . ')\\b/', $v['url'], $c); }, $str);
Output:
<p>Just a test: https://www.getname.com https://www.testname.com
Demo on 3v4l.org
Update
To change the text into links, you need to use this:
echo array_reduce($keywords,
function ($c, $v) {
return preg_replace('/\\b(' . $v['slug'] . ')\\b/',
'$1', $c);
},
$str);
Output:
<p>Just a test: getName testName
Updated demo
Update 2
Because some of the links that are being substituted include words that are also values of slug, it's necessary to do all the replacements at once using the array format of strtr. We build an array of patterns and replacements using array_column, array_combine and array_map, then pass that to strtr:
$reps = array_combine(array_column($keywords, 'slug'),
array_map(function ($k) { return '' . $k['slug'] . ''; }, $keywords
));
$newstr = strtr($str, $reps);
New demo
First you need to change structure of array to key/value using loop that result stored in $newKeywords. Then using preg_replace_callback() select every word in string and check that it exist in key of array. If exist, wrap it in anchor tag.
$newKeywords = [];
foreach ($keywords as $keyword)
$newKeywords[$keyword['slug']] = $keyword['url'];
$newStr = preg_replace_callback("/(\w+)/", function($m) use($newKeywords){
return isset($newKeywords[$m[0]]) ? "<a href='{$newKeywords[$m[0]]}'>{$m[0]}</a>" : $m[0];
}, $str);
Output:
<p>Just a test: <a href='https://www.getname.com'>getName</a> <a href='https://www.testname.com'>testName</a></p>
Check result in demo
My answer uses preg_replace as does Nick's above.
It relies on the patterns and replacements being equally sized arrays, with corresponding patterns and replacements.
Word boundaries need to be respected, which I doubt you can do with a simple string replacement.
<?php
$keywords = [
0=>['id'=>1,'slug'=>'foo','url'=>'https://www.example.com/foo'],
1=>['id'=>2,'slug'=>'bar','url'=>'https://www.example.com/bar'],
2=>['id'=>3,'slug'=>'baz','url'=>'https://www.example.com/baz'],
];
foreach ($keywords as $item)
{
$patterns[] = '#\b(' . $item['slug'] . ')\b#i';
$replacements[] = '$1';
}
$html = "<p>I once knew a barbed man named <i>Foo</i>, he often visited the bar.</p>";
print preg_replace($patterns, $replacements, $html);
Output:
<p>I once knew a barbed man named <i>Foo</i>, he often visited the bar.</p>
This is my answer: thanks for #Nick
$content = array_reduce($keywords , function ($c, $v) {
return preg_replace('/(>[^<>]*?)(' . $v['slug'] . ')([^<>]*?<)/', '$1$2$3', $c);
}, $str);
I've been using PHP for a while and came across an issue where turning a string into an array (explode), and then simply removing system output characters around each element was not easy to achieve.
I have a string of categories where the output needs to be handled:
2;#Ecosystems;#3;#Core Science Systems (CSS);#4;#Energy and Minerals;#5;#Director
I have tried this particular code below:
$text = "2;#Ecosystems;#3;#Core Science Systems (CSS);#4;#Energy and Minerals;#5;#Director";
$explode = explode('#' , $text);
foreach ($explode as $key => $value)
{
ob_start();
echo ''.$value.'';
$myStr = ob_get_contents();
ob_end_clean();
}
echo "$myStr"
The only element returned is:
Director
Can someone point me in the right direction. I'd like to view the string like this:
Ecosystems; Core Science Systems (CSS); Energy and Minerals; Director
$myStr = ob_get_contents();
This will replace $myStr. What you're probably looking to do is add to it:
$myStr .= ob_get_contents();
Though looking at your required output, your code is not going to achieve what you want, because you're not removing the preceding part e.g. #1;.
Try this
$text = "2;#Ecosystems;#3;#Core Science Systems (CSS);#4;#Energy and Minerals;#5;#Director";
$text = preg_replace('/(#?[0-9];#)/', ' ', $text);
echo $text;
Output: Ecosystems; Core Science Systems (CSS); Energy and Minerals; Director
Your problem is not question-related, you overwrite your buffer with each foreach iteration, the fix is
$myStr .= ob_get_contents();
For this exact example you give you could change the explode to split on ;#
$text = "2;#Ecosystems;#3;#Core Science Systems (CSS);#4;#Energy and Minerals;#5;#Director";
$categories = array();
$explode = explode(';#' , $text);
foreach ($explode as $key => $value)
{
if (!is_numeric($value)) {
$categories[] = $value;
}
}
echo implode("; ", $categories);
The reason is that you place both ob_start() and ob_end_clean() inside the loop. Place them outside the loop:
ob_start();
foreach ($explode as $key => $value)
{
echo ''.$value.'';
$myStr = ob_get_contents();
}
ob_end_clean();
echo "$myStr";
I would use preg_split and do it like this:
$result = implode(' ', preg_split('/#?\d+;#/', $text, null, PREG_SPLIT_NO_EMPTY));
this solves the problem, you can fine-tune the output:
$text = "2;#Ecosystems;#3;#Core Science Systems (CSS);#4;#Energy and Minerals;#5;#Director";
$explode = explode('#' , $text);
$myStr = '';
foreach ($explode as $key => $value)
{
$myStr .= $value;
}
echo "$myStr"
$arr = explode("#", $text);
You can then echo the array in different ways
echo $arr[0] <= the number represents the index of the array value.
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
For a content with the format:
KEY=VALUE
like:
LISTEN=I am listening.
I need to do some replacing using regex. I want this regular expression to replace anything before the = with $key (making it have to be from beginning of line so a key like 'EN' wont replace a key like "TOKEN".
Here's what I'm using, but it doesn't seem to work:
$content = preg_replace('~^'.$key.'\s?=[^\n$]+~iu',$newKey,$content);
$content = "foo=one\n"
. "bar=two\n"
. "baz=three\n";
$keys = array(
'foo' => 'newFoo',
'bar' => 'newBar',
'baz' => 'newBaz',
);
foreach ( $keys as $oldKey => $newKey ) {
$oldKey = preg_quote($oldKey, '#');
$content = preg_replace("#^{$oldKey}( ?=)#m", "{$newKey}\\1", $content);
}
echo $content;
Output:
newFoo=one
newBar=two
newBaz=three
$str = 'LISTEN=I am listening.';
$new_key = 'ÉCOUTER';
echo preg_replace('/^[^=]*=/', $new_key . '=', $str);
If I understood your question well, you need to switch the multi-line mode on using m modifier.
$content = preg_replace('/^'.preg_quote($key, '/').'(?=\s?=)/ium', $newKey, $content);
By the way I do recommend to escape the $key using preg_quote to avoid unexpected results.
So if the source content is this:
KEY1=VALUE1
HELLO=WORLD
KEY3=VALUE3
The result will be this (if $key=HELLO and $newKey=BYE):
KEY1=VALUE1
BYE=WORLD
KEY3=VALUE3
This should do the trick.
\A is the start of a line, and the parentheses is for grouping things to keep/replace.
$new_content = preg_replace("/\A(.*)(=.*)/", "$key$2", $content);
$content = 'LISTEN=I am listening.';
$key = 'LISTEN';
$newKey = 'NEW';
$content = preg_replace('~^'.$key.'(\s?=)~iu',$newKey.'$1',$content);
echo $content;
output is NEW=I am listening.
But is does not change on a partial match
$content = 'LISTEN=I am listening.';
$key = 'TEN';
$new_key = 'NEW';
$content = preg_replace('~^'.$key.'(\s?=)~iu',$newKey.'$1',$content);
echo $content;
Output is LISTEN=I am listening.