Use a regex match as an array pointer - php

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

Related

How to invert preg_match_all php

How can I invert pre_match_all, so the output of the code below is "you" instead of "hello" and "world"?
$text1 = array ('you', 'hello', 'WORLD');
$text2 = "Hello world";
//preg_match
foreach ($text1 as $text) {
if (preg_match_all("~\b$text\b~i", $text2, $match)) {
$match = $match[0];
echo "<pre>";
print_r($match);
echo "</pre>";
}
}
Split the string by non-word characters and use array_udiff with strcasecmp as callback:
$words = ['you', 'hello', 'WORLD'];
$str = "Hello world toto";
print_r(array_udiff($words, preg_split('~\W+~', $str), 'strcasecmp'));
// Array
// (
// [0] => you
// )
You don't need preg_match_all(), preg_match() is enough (it returns 1 if it finds a match, 0 otherwise).
You also don't need the matching substrings, it's enough to know if it found a word in the text or not.
$words = array('you', 'hello', 'WORLD');
$text = "Hello world";
// Filter $words, keep only the items that are not present in $text
$missing = array_filter(
$words,
function($w) use ($text) {
// return TRUE when $w is not in $text
return preg_match('/\b'.preg_quote($w, '/').'\b/i', $text) == 0;
});
print_r($missing);
You can use str_ireplace which is case insensitive version of str_replace.
If you replace with nothing, what is left is what is not in $text2.
$text1 = array ('you', 'hello', 'WORLD');
$text2 = "Hello world";
$text2 = explode(" ", $text2);
echo str_ireplace($text2, "", implode("",$text1));
// you
https://3v4l.org/T8o2l
Another method would be to use array_diff and preg_grep.
Preg_grep matches with regex the words from text2 in text1 case insensitive and returns what is matching.
Then I use array_diff to see what is different from $text1 and the return from preg_grep.
$text1 = array ('you', 'hello', 'WORLD');
$text2 = "Hello world";
$text2 = explode(" ", $text2);
Var_dump(array_diff($text1, preg_grep("/" . Implode("|", $text2) . "/i", $text1)));
https://3v4l.org/WOuh6

php extract a sub-string before and after a character from a string

need to extract an info from a string which strats at 'type-' and ends at '-id'
IDlocationTagID-type-area-id-492
here is the string, so I need to extract values : area and 492 from the string :
After 'type-' and before '-id' and after 'id-'
You can use the preg_match:
For example:
preg_match("/type-(.\w+)-id-(.\d+)/", $input_line, $output_array);
To check, you may need the service:
http://www.phpliveregex.com/
P.S. If the function preg_match will be too heavy, there is an alternative solution:
$str = 'IDlocationTagID-type-area-id-492';
$itr = new ArrayIterator(explode('-', $str));
foreach($itr as $key => $value) {
if($value === 'type') {
$itr->next();
var_dump($itr->current());
}
if($value === 'id') {
$itr->next();
var_dump($itr->current());
}
}
This is what you want using two explode.
$str = 'IDlocationTagID-type-area-id-492';
echo explode("-id", explode("type-", $str)[1])[0]; //area
echo trim(explode("-id", explode("type-", $str)[1])[1], '-'); //492
Little Simple ways.
echo explode("type-", explode("-id-", $str)[0])[1]; // area
echo explode("-id-", $str)[1]; // 492
Using Regular Expression:
preg_match("/type-(.*)-id-(.*)/", $str, $output_array);
print_r($output_array);
echo $area = $output_array[1]; // area
echo $fnt = $output_array[2]; // 492
You can use explode to get the values:
$a = "IDlocationTagID-type-area-id-492";
$data = explode("-",$a);
echo "Area ".$data[2]." Id ".$data[4];
$matches = null;
$returnValue = preg_match('/type-(.*?)-id/', $yourString, $matches);
echo($matches[1]);

PHP Get the word replaced by preg_replace

How can I get the replaced word by preg_replace() function.
preg_replace('/[#]+([A-Za-z0-9-_]+)/', '$0', $post );
I want to get $1 variable so that I can user it further.
Capture it before you replace the expression:
// This is where the match will be kept
$matches = array();
$pattern = '/[#]+([A-Za-z0-9-_]+)/';
// Check if there are matches and capture the user (first group)
if (preg_match($pattern, $post, $matches)) {
// First match is the user
$user = $matches[1];
// Do the replace
preg_replace($pattern, '$0', $post );
}
This isn't possible with preg_replace() as it returns the finished string/array, but does not preserve the replaced phrases. You can use preg_replace_callback() to manually achieve this.
$pattern = '/[#]+([A-Za-z0-9-_]+)/';
$subject = '#jurgemaister foo #hynner';
$tokens = array();
$result = preg_replace_callback(
$pattern,
function($matches) use(&$tokens) {
$tokens[] = $matches[1];
return ''.$matches[0].'';
},
$subject
);
echo $result;
// #jurgemaister foo #hynner
print_r($tokens);
// Array
// (
// [0] => jurgemaister
// [1] => hynner
// )
You should use preg_match in addition to preg_replace. preg_replace is just for replacing.
$regex = '/[#]+([A-Za-z0-9-_]+)/';
preg_match($regex, $post, $matches);
preg_replace($regex, '$0', $post );
You can't do that with preg_replace, but you can do it with preg_replace_callback:
preg_replace_callback($regex, function($matches){
notify_user($matches[1]);
return "<a href='/$matches[1]' target='_blank'>$matches[0]</a>";
}, $post);
replace notify_user with whatever you would call to notify the user.
This can also be modified to check whether the user exists and replace only valid mentions.

preg_match, str_replace and all that jazz

I have a string which contains several keywords in square backets which I want to identify, extract, and replace with something else:
For example:
'You will win [winnings] or [slice].'
I want to identify all the terms within the squares, take those terms and replace them with certain values.
So it should end up like this:
'You will win 100 or 95%.'
Any ideas?
piece of cake
$search = array('[winnings]', '[slice]');
$replace = array(100, '95%');
echo str_replace($search, $replace, 'You will win [winnings] or [slice].');
$replacements = array(
'winnings' => '100'
, 'slice' => '95%'
, 'foobar' => 'Sean Bright'
);
$subject = '[foobar], You will win [winnings] or [slice]!';
$result = preg_replace_callback(
'/\[([^\]]+)\]/',
function ($x) use ($replacements) {
if (array_key_exists($x[1], $replacements))
return $replacements[$x[1]];
return '';
},
$subject);
echo $result;
Note that this will completely fall apart if you have unbalanced brackets (i.e. [[foo])
For PHP versions less than 5.3:
$replacements = array(
'winnings' => '100'
, 'slice' => '95%'
, 'foobar' => 'Sean Bright'
);
function do_replacement($x)
{
global $replacements;
if (array_key_exists($x[1], $replacements))
return $replacements[$x[1]];
return '';
}
$subject = '[foobar], You will win [winnings] or [slice]!';
$result = preg_replace_callback(
'/\[([^\]]+)\]/',
'do_replacement',
$subject);
echo $result;
And if you want to use a regex to find matches:
$content = "You will win [winnings] or [slice].";
preg_match_all('/\[([a-z]+)\]/i', $content, $matches);
$content = str_replace($matches[0], array('100', '95%'), $content);
var_dump($content);

how to do a preg_replace on a string in php?

i have some simple code that does a preg match:
$bad_words = array('dic', 'tit', 'fuc',); //for this example i replaced the bad words
for($i = 0; $i < sizeof($bad_words); $i++)
{
if(preg_match("/$bad_words[$i]/", $str, $matches))
{
$rep = str_pad('', strlen($bad_words[$i]), '*');
$str = str_replace($bad_words[$i], $rep, $str);
}
}
echo $str;
So, if $str was "dic" the result will be '*' and so on.
Now there is a small problem if $str == f.u.c. The solution might be to use:
$pattern = '~f(.*)u(.*)c(.*)~i';
$replacement = '***';
$foo = preg_replace($pattern, $replacement, $str);
In this case i will get ***, in any case. My issue is putting all this code together.
I've tried:
$pattern = '~f(.*)u(.*)c(.*)~i';
$replacement = 'fuc';
$fuc = preg_replace($pattern, $replacement, $str);
$bad_words = array('dic', 'tit', $fuc,);
for($i = 0; $i < sizeof($bad_words); $i++)
{
if(preg_match("/$bad_words[$i]/", $str, $matches))
{
$rep = str_pad('', strlen($bad_words[$i]), '*');
$str = str_replace($bad_words[$i], $rep, $str);
}
}
echo $str;
The idea is that $fuc becomes fuc then I place it in the array then the array does its jobs, but this doesn't seem to work.
First of all, you can do all of the bad word replacements with one (dynamically generated) regex, like this:
$bad_words = array('dic', 'tit', 'fuc',);
$str = preg_replace_callback("/\b(?:" . implode( '|', $bad_words) . ")\b/",
function( $match) {
return str_repeat( '*', strlen( $match[0]));
}, $str);
Now, you have the problem of people adding periods in between the word, which you can search for with another regex and replace them as well. However, you must keep in mind that . matches any character in a regex, and must be escaped (with preg_quote() or a backslash).
$bad_words = array_map( function( $el) {
return implode( '\.', str_split( $el));
}, $bad_words);
This will create a $bad_words array similar to:
array(
'd\.i\.c',
't\.i\.t',
'f\.u\.c'
)
Now, you can use this new $bad_words array just like the above one to replace these obfuscated ones.
Hint: You can make this array_map() call "better" in the sense that it can be smarter to catch more obfuscations. For example, if you wanted to catch a bad word separated with either a period or a whitespace character or a comma, you can do:
$bad_words = array_map( function( $el) {
return implode( '(?:\.|\s|,)', str_split( $el));
}, $bad_words);
Now if you make that obfuscation group optional, you'll catch a lot more bad words:
$bad_words = array_map( function( $el) {
return implode( '(?:\.|\s|,)?', str_split( $el));
}, $bad_words);
Now, bad words should match:
f.u.c
f,u.c
f u c
fu c
f.uc
And many more.

Categories