I am trying to create a regex to replace a string. Here is my pattern:
\{mailMerge: details_activity_number\\}
When I do a search like this on a string like this:
hello {mailMerge: details_activity_number\}world
its fine. But, if there's a line break like this:
hello \{
mailMerge: details_activity_number\} world
it breaks. Here is my code in PHP:
$pattern = '\{mailMerge: 'mailMerge: details_activity_number'\}';
$content = str_replace($pattern, $value, $content);
Can anyone help me with creating a pattern that would take into consideration possible line breaks/white spaces/etc to guarantee a match?
thanks
EDIT
private function findAndReplace($content, $mergedArray){
$test=$content;
try{
foreach($mergedArray as $ArrayKey => $ArrayValue){
foreach ($ArrayValue as $key => $value) {
$pattern = "\{\s*mailMerge:\s+". $key ."\s*\\\}";
if($value){
$test = preg_replace($pattern, $value, $test);
}else{
$test = preg_replace($pattern, "No Value Exists", $test);
}
}
}
}catch(Exception $e){
throw $e;
}
return $test;
}
The first version that you posted doesn't allow for any space between { and m. You need to do something like this:
\{\s*mailMerge:\s+details_activity_number\s*\\\}
The \s* means "match zero or more spaces (or other white space, like new lines) here." \s+ means "match one or more spaces (or other white space, like new lines) here."
NOTE: Your code above uses str_replace, but you are trying to do a regex replace. You need to use preg_replace instead of str_replace, like in this code:
$content = "\{mailMerge: 'mailMerge: details_activity_number'\}";
$content = preg_replace('/\{\s*mailMerge:\s+details_activity_number\s*\\\}/m', $value, $content);
EDIT BASED ON COMMENTS: Try this; it is working for me.
$value = "foo barrrrrr";
$content = "hello
{mailMerge: details_activity_number\} world";
$content = preg_replace("/\\\\?\\{\s*mailMerge:\s+details_activity_number\s*\\\\?\\}/m", $value, $content);
echo $content; // produces "hello foo barrrrrr world"
Related
I am using a WordPress plugin named Acronyms (https://wordpress.org/plugins/acronyms/). This plugin replaces acronyms with their description. It uses a PHP PREG_REPLACE function.
The issue is that it replaces the acronyms contained in a <pre> tag, which I use to present a source code.
Could you modify this expression so that it won't replace acronyms contained inside <pre> tags (not only directly, but in any moment)? Is it possible?
The PHP code is:
$text = preg_replace(
"|(?!<[^<>]*?)(?<![?.&])\b$acronym\b(?!:)(?![^<>]*?>)|msU"
, "<acronym title=\"$fulltext\">$acronym</acronym>"
, $text
);
You can use a PCRE SKIP/FAIL regex trick (also works in PHP) to tell the regex engine to only match something if it is not inside some delimiters:
(?s)<pre[^<]*>.*?<\/pre>(*SKIP)(*F)|\b$acronym\b
This means: skip all substrings starting with <pre> and ending with </pre>, and only then match $acronym as a whole word.
See demo on regex101.com
Here is a sample PHP demo:
<?php
$acronym = "ASCII";
$fulltext = "American Standard Code for Information Interchange";
$re = "/(?s)<pre[^<]*>.*?<\\/pre>(*SKIP)(*F)|\\b$acronym\\b/";
$str = "<pre>ASCII\nSometext\nMoretext</pre>More text \nASCII\nMore text<pre>More\nlines\nASCII\nlines</pre>";
$subst = "<acronym title=\"$fulltext\">$acronym</acronym>";
$result = preg_replace($re, $subst, $str);
echo $result;
Output:
<pre>ASCII</pre><acronym title="American Standard Code for Information Interchange">ASCII</acronym><pre>ASCII</pre>
It is also possible to use preg_split and keep the code block as a group, only replace the non-code block part then combine it back as a complete string:
function replace($s) {
return str_replace('"', '"', $s); // do something with `$s`
}
$text = 'Your text goes here...';
$parts = preg_split('#(<\/?[-:\w]+(?:\s[^<>]+?)?>)#', $text, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$text = "";
$x = 0;
foreach ($parts as $v) {
if (trim($v) === "") {
$text .= $v;
continue;
}
if ($v[0] === '<' && substr($v, -1) === '>') {
if (preg_match('#^<(\/)?(?:code|pre)(?:\s[^<>]+?)?>$#', $v, $m)) {
$x = isset($m[1]) && $m[1] === '/' ? 0 : 1;
}
$text .= $v; // this is a HTML tag…
} else {
$text .= !$x ? replace($v) : $v; // process or skip…
}
}
return $text;
Taken from here.
I'm using the code given on this page to look through a string and turn the URL into an HTML link.
It works quite well, but there is a little issue with the "replace" part of it.
The problem occurs when I have almost identical links. For example:
https://example.com/page.php?goto=200
and
https://example.com/page.php
Everything will be fine with the first link, but the second will create a <a> tag in the first <a> tag.
First run
https://example.com/page.php?goto=200
Second
https://example.com/page.php?goto=200">https://example.com/page.php?goto=200</a>
Because it's also replacing the html link just created.
How do I avoid this?
<?php
function turnUrlIntoHyperlink($string){
//The Regular Expression filter
$reg_exUrl = "/(?i)\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/";
// Check if there is a url in the text
if(preg_match_all($reg_exUrl, $string, $url)) {
// Loop through all matches
foreach($url[0] as $newLinks){
if(strstr( $newLinks, ":" ) === false){
$link = 'http://'.$newLinks;
}else{
$link = $newLinks;
}
// Create Search and Replace strings
$search = $newLinks;
$replace = ''.$link.'';
$string = str_replace($search, $replace, $string);
}
}
//Return result
return $string;
}
?>
You need to add a whitespace identifier \s in your regex at the start, also remove \b because \b only returns the last match.
You regex can written as:
$reg_exUrl = "/(?i)\s((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/"
check this one: https://regex101.com/r/YFQPlZ/1
I have change the replace part a bit, since I couldn't get the suggested regex to work.
Maybe it can be done better, but I'm still learning :)
function turnUrlIntoHyperlink($string){
//The Regular Expression filter
$reg_exUrl = "/(?i)\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/";
// Check if there is a url in the text
if(preg_match_all($reg_exUrl, $string, $url)) {
// Loop through all matches
foreach($url[0] as $key => $newLinks){
if(strstr( $newLinks, ":" ) === false){
$url = 'https://'.$newLinks;
}else{
$url = $newLinks;
}
// Create Search and Replace strings
$replace .= ''.$url.',';
$newLinks = '/'.preg_quote($newLinks, '/').'/';
$string = preg_replace($newLinks, '{'.$key.'}', $string, 1);
}
$arr_replace = explode(',', $replace);
foreach ($arr_replace as $key => $link) {
$string = str_replace('{'.$key.'}', $link, $string);
}
}
//Return result
return $string;
}
Trying to write a function that will replace #something# and #anything# in any string with items in my db that match the name "something" and "anything".
This should work for no matter how many different #some-name# there are in my string. Below is what I have so far and it's working, although only the last (#anything#) is being replaced with the correct code when I load in my browser.
Please keep in mind that I'm learning, so I may be completely off on how to go about this. If there is a better way, I'm all ears.
HTML (String)
<p>This is "#something#" I wanted to replace with code from my database. Really, I could have "#anything#" between my pound sign tags and it should be replaced with text from my database</p>
OUTPUT I'm Getting
This is "#something#" I want to replace with code from my database. Really, I could have "Any Name" between my pound sign tags and it should be replaced with text from my database
DESIRED OUTPUT
This is "The Code" I want to replace with code from my database. Really, I could have "Any Name" between my pound sign tags and it should be replaced with text from my database
FUNCTION in CMS class a.php
public function get_snippets($string) {
$regex = "/#(.*?)#/";
preg_match_all($regex, $string, $names);
$names = $names[1];
foreach ($names as $name){
$find_record = Snippet::find_snippet_code($name);
$db_name = $find_record->name;
if($name == $db_name) {
$snippet_name = "/#".$name."#/";
$code = $find_record->code;
}
}
echo preg_replace($snippet_name, $code, $string);
}
FUNCTION in Snippet class b.php
public static function find_snippet_code($name) {
global $database;
$result_array = static::find_by_sql("SELECT * from ".static::$table_name." WHERE name = '{$name}'");
return !empty($result_array) ? array_shift($result_array) : false;
}
It's because your preg_replace occurs outside of the foreach() loop, so it only happens once.
Here is a working example based on your code which returns $string.
Note that I also use PREG_SET_ORDER which gives me each match as its own array:
function get_snippets($string) {
$regex = '/#([^#]+)#/';
$num_matches = preg_match_all($regex, $string, $matches, PREG_SET_ORDER);
if ($num_matches > 0) {
foreach ($matches as $match) {
// Each match is an array consisting of the token we matched and the 'name' without the special characters
list($token, $name) = $match;
// See if there is a matching record for 'name'
$find_record = Snippet::find_snippet_code($name);
// This step might be redundant, but compare name with the record name
if ($find_record->name == $name) {
// Replace all instances of #token# with the code from the matched record
$string = preg_replace('/'.$token.'/', $find_record->code, $string);
}
}
}
return $string;
}
What you're looking for is preg_replace_callback():
public function get_snippets($string)
{
$regex = "/#(.*?)#/";
return preg_replace_callback($regex, function($match) {
$find_record = Snippet::find_snippet_code($match[1]);
return $find_record === false ? '' : $find_record->code;
}, $string);
}
I am trying to identify a blank lines in a string. Below is my attempt in PHP:
<?php
$alldevs = $_POST['devs'];
$devices = explode("\n", $alldevs);
foreach($devices as $device) {
if(!empty($device)){
echo $device;
} else {
echo "end of value";
}
}
?>
When I input the following:
1
2
3
4
I get this output:
1
2
3
4
But what it should be outputting is this:
1
2
3
end of value
end of value
4
What am I doing wrong?
They probably contain a \r (which is posted on new lines in text areas for some browsers/OS'es), a space or a tab character. You can get rid of these by using the trim() command:
<?php
$alldevs = $_POST['devs'];
$devices = explode("\n", $alldevs);
foreach ($devices as $device) {
$device = trim($device); //Trim that string!
if(!empty($device))
{
echo $device;
}
else
{
echo "end of value";
}
}
?>
Oh, and PLEASE indent your code for your own and everybody elses sake.
Alternatively, split up your string by using regex:
$devices = preg_split("/(\r\n|\n\r|\r|\n)/", $alldevs);
This should give you what you want:
if( trim($device) !== '' )
{
echo $device."<br>";
}
else
{
echo "end of value"."<br>";
}
Outputs:
1
2
3
end of value
4
I think your problem is with \r\n
Use this code
$alldevs = str_replace("\r", '', $alldevs);
Then explode it, and also use trim for clean spaces
$alldevs = trim($alldevs);
first, please read dealing with line endings and wikipedia newline
second, you are using string explode when you should use a function like preg_match_all
code should look something like this (mind the bad regex please):
<?php
$string = $_POST['devs'];
preg_match_all('%^([^\n\r]*)[\n\r]?$%im', $string, $matches);
foreach ($matches[1] as $match) {
if($match) {
var_dump($match);
} else {
echo 'empty line' . PHP_EOL;
}
}
adjust this code to fit your needs, i left a var_dump there so you could see the string length.
Add a check for a string with more than 0 characters,
if(!empty($device) && strlen($device)>0) {
I would also try a use case with \r\n on your line-breaks, you'll run into that as well.
you can try this
$devices = preg_replace('/^\s*$/','end of value',explode("\n",$alldevs));
foreach($devices as $device) {
echo $device, "\n";
}
I want to replace some numbers in a string with the content of the array in the position which this number points to.
For example, replace "Hello 1 you are great", with "Hello myarray[1] you are great"
I was doing the next: preg_replace('/(\d+)/','VALUE: ' . $array[$1],$string);
But it does not work. How could I do it?
You should use a callback.
<?php
$str = 'Hello, 1!';
$replacements = array(
1 => 'world'
);
$str = preg_replace_callback('/(\d+)/', function($matches) use($replacements) {
if (array_key_exists($matches[0], $replacements)) {
return $replacements[$matches[0]];
} else {
return $matches[0];
}
}, $str);
var_dump($str); // 'Hello, world!'
Since you are using a callback, in the event that you actually want to use a number, you might want to encode your strings as {1} or something instead of 1. You can use a modified match pattern:
<?php
// added braces to match
$str = 'Hello, {1}!';
$replacements = array(
1 => 'world'
);
// added braces to regex
$str = preg_replace_callback('/\{(\d+)\}/', function($matches) use($replacements) {
if (array_key_exists($matches[1], $replacements)) {
return $replacements[$matches[1]];
} else {
// leave string as-is, with braces
return $matches[0];
}
}, $str);
var_dump($str); // 'Hello, world!'
However, if you are always matching known strings, you may want to use #ChrisCooney's solution because it offers less opportunity to screw up the logic.
The other answer is perfectly fine. I managed it this way:
$val = "Chris is 0";
// Initialise with index.
$adj = array("Fun", "Awesome", "Stupid");
// Create array of replacements.
$pattern = '!\d+!';
// Create regular expression.
preg_match($pattern, $val, $matches);
// Get matches with the regular expression.
echo preg_replace($pattern, $adj[$matches[0]], $val);
// Replace number with first match found.
Just offering another solution to the problem :)
$string = "Hello 1 you are great";
$replacements = array(1 => 'I think');
preg_match('/\s(\d)\s/', $string, $matches);
foreach($matches as $key => $match) {
// skip full pattern match
if(!$key) {
continue;
}
$string = str_replace($match, $replacements[$match], $string);
}
<?php
$array = array( 2 => '**', 3 => '***');
$string = 'lets test for number 2 and see 3 the result';
echo preg_replace_callback('/(\d+)/', 'replaceNumber', $string);
function replaceNumber($matches){
global $array;
return $array[$matches[0]];
}
?>
output
lets test for number ** and see *** the result