I have an array $track['context'] This outputs the following
常州, 的, 妈咪ZA, 已揽件快件已从, 常州, 发出快件到达
Each one of these are tracking details.
I am running the array through the following code to try and run a preg_match for each item that is inside of $track['context'] then replace if a string from $badWords is present
$badWords = ['常州', '的']; // I would want these to end up being ['one', 'two']
$arrayToCheck = $track['context'];
foreach ($badWords as $badWord) {
if (preg_match("/($badWord)/", $arrayToCheck)) {
// Do I run my preg_match function here?
}
}
I would suggest a data structure for the bad words, where the word is the key and the replacement the value in an associative array.
Then you could loop over your content array, and do the replacement with a callback function:
// Sample data:
$track['context'] = array(
'qdf 常州',
'fdhlkjfq fdkq ',
'的 fdsqfsf'
);
// Make a translation table for the bad words:
$badWords = [
'常州' => 'one',
'的' => 'two'
];
// Build a regular expression that matches any of the above words:
$regexp = "/\b(" . implode('|', array_map('preg_quote', array_keys($badWords))) . ")\b/u";
// Iterate over the content
foreach ($track['context'] as &$subject) {
$subject = preg_replace_callback($regexp, function($matches) use ($badWords) {
// Replace the matched bad word with what we have mapped for it:
return $badWords[$matches[0]];
}, $subject);
}
// Output results:
print_r ($track['context']);
See it run on eval.in
First of all, make $badWords an array, like:
$badWords = array('bad_word1', 'bad_word2');
Second, I would use the strpos function, which is used to find the occurrence of one string inside other.
Lastly, remember to set $noBadWordsFound to false in your code.
Related
I have a problem. I don't know what could be the cause. What I want to do is to know if an element of an array has a certain word, and I use this regular expression /.*example.*/, and this is the code:
$array = ['example1', '2example', 'no'];
$matches = [];
$var = "example";
foreach($array as $element)
{
preg_match("/.*$var.*/", $element, $matches);
}
But when I run the above code and see the value of $matches it is an empty array. What am I doing wrong?
That's because you are looping through your $array and probably print the result after the loop.
So $matches just includes the matching elements of the last item in your $array.
But because 'no' is the last element, and it doesn't fulfill the regex requirements, $matches is empty.
To have a better understanding of what is happening, try to use print_r($matches) within your loop, after you called preg_matches().
And after that, try to call it after your loop and see the difference.
You need two variables. One is the result of the current match, and another is a list of all the matches. After each call you can push the result of the current match to the list.
$array = ['example1', '2example', 'no'];
$matches = [];
$var = "example";
foreach($array as $element)
{
if (preg_match("/.*$var.*/", $element, $match)) {
$matches[] = $match[0];
}
}
print_r($matches);
I have a string which contains certain number of #{number} structures. For example:
#328_#918_#1358
SKU:#666:#456
TEST--#888/#982
For each #{number} structure, I have to replace it with a known string.
For the first example:
#328_#918_#1358
I have the following strings:
328="foo"
918="bar"
1358"arg"
And the result should be:
foo_bar_arg
How do I achieve such effect? My current code looks like that:
$matches = array();
$replacements = array();
// starting string
$string = "#328_#918:#1358";
// getting all the numbers from the string
preg_match_all("/\#[0-9]+/", $string, $matches);
// getting rid of #
foreach ($matches[0] as $key => &$feature) {
$feature = preg_replace("/#/", "", $feature);
} // end foreach
// obtaining the replacement values
foreach ($matches[0] as $key => $value) {
$replacement[$value] = "fizz"; // here the value required for replacement is obtained
} // end foreach
But I have no idea how to actually perform a replacement in $string variable using values from $replacement table. Any help is much appreciated!
You can use a preg_replace_callback solution:
$string = '#328_#918:#1358
SKU:#666:#456
TEST--#888/#982';
$replacements = [328=>"foo", 918=>"bar", 1358=>"arg"];
echo preg_replace_callback("/#([0-9]+)/", function ($m) use ($replacements) {
return isset($replacements[$m[1]]) ? $replacements[$m[1]] : $m[0];
}
,$string);
See the PHP demo.
The #([0-9]+) regex will match all non-overlapping occurrences of # and one or more digits right after capturing them into Group 1. If there is an item in the replacements associative array with the numeric key, the whole match is replaced with the corresponding value. Else, the match is returned so that no replacement could occur and the match does not get removed.
I have the following method, which checks for the word 'example' in a text, and if it finds is, it wraps a span around it:
function highlightWords($dreams) {
$wrap_before = '<span class="highlight_match">';
$wrap_after = '</span>';
$key_words = 'example';
$dreams = json_decode($dreams);
foreach ($dreams as &$value) {
$value->dream = preg_replace("/($key_words)/i",
"$wrap_before$1$wrap_after", $value->dream);
}
return $dreams;
}
I've tried to modify the $key_words variable to an array, so I could give multiple words as parameter, but it always gives back an error. Can I even do this with this approach?
Use implode() to convert your array of keywords into a string that you can use as your regex.
It appears that you want to do a whole word match on one of a number of keywords, so use the alternation operator (the | character) as a delimiter.
For example, given an array of:
$key_words = ['foo', 'bar', 'baz'];
$key_words = implode('|', $key_words);
Yields the following string:
foo|bar|baz
Which you can then use in place to create your regex of key words:
// /(foo|bar|baz)/i
preg_replace("/($key_words)/i",
"$wrap_before$1$wrap_after", $value->dream);
Hope this helps :)
I am currently working on a small script to convert data coming from an external source. Depending on the content I need to map this data to something that makes sense to my application.
A sample input could be:
$input = 'We need to buy paper towels.'
Currently I have the following approach:
// Setup an assoc_array what regexp match should be mapped to which itemId
private $itemIdMap = [ '/paper\stowels/' => '3746473294' ];
// Match the $input ($key) against the $map and return the first match
private function getValueByRegexp($key, $map) {
$match = preg_grep($key, $map);
if (count($match) > 0) {
return $match[0];
} else {
return '';
}
}
This raises the following error on execution:
Warning: preg_grep(): Delimiter must not be alphanumeric or backslash
What am I doing wrong and how could this be solved?
In preg_grep manual order of arguments is:
string $pattern , array $input
In your code $match = preg_grep($key, $map); - $key is input string, $map is a pattern.
So, your call is
$match = preg_grep(
'We need to buy paper towels.',
[ '/paper\stowels/' => '3746473294' ]
);
So, do you really try to find string We need to buy paper towels in a number 3746473294?
So first fix can be - swap'em and cast second argument to array:
$match = preg_grep($map, array($key));
But here comes second error - $itemIdMap is array. You can't use array as regexp. Only scalar values (more strictly - strings) can be used. This leads you to:
$match = preg_grep($map['/paper\stowels/'], $key);
Which is definitely not what you want, right?
The solution:
$input = 'We need to buy paper towels.';
$itemIdMap = [
'/paper\stowels/' => '3746473294',
'/other\sstuff/' => '234432',
'/to\sbuy/' => '111222',
];
foreach ($itemIdMap as $k => $v) {
if (preg_match($k, $input)) {
echo $v . PHP_EOL;
}
}
Your wrong assumption is that you think you can find any item from array of regexps in a single string with preg_grep, but it's not right. Instead, preg_grep searches elements of array, which fit one single regexp. So, you just used the wrong function.
$string = 'test check one two test3';
$result = mb_eregi_replace ( 'test|test2|test3' , '<$1>' ,$string ,'i');
echo $result;
This should deliver: <test> check one two <test3>
Is it possible to get, that test and test3 was found, without using another match function ?
You can use preg_replace_callback instead:
$string = 'test check one two test3';
$matches = array();
$result = preg_replace_callback('/test|test2|test3/i' , function($match) use ($matches) {
$matches[] = $match;
return '<'.$match[0].'>';
}, $string);
echo $result;
Here preg_replace_callback will call the passed callback function for each match of the pattern (note that its syntax differs from POSIX). In this case the callback function is an anonymous function that adds the match to the $matches array and returns the substitution string that the matches are to be replaced by.
Another approach would be to use preg_split to split the string at the matched delimiters while also capturing the delimiters:
$parts = preg_split('/test|test2|test3/i', $string, null, PREG_SPLIT_DELIM_CAPTURE);
The result is an array of alternating non-matching and matching parts.
As far as I know, eregi is deprecated.
You could do something like this:
<?php
$str = 'test check one two test3';
$to_match = array("test", "test2", "test3");
$rep = array();
foreach($to_match as $val){
$rep[$val] = "<$val>";
}
echo strtr($str, $rep);
?>
This too allows you to easily add more strings to replace.
Hi following function used to found the any word from string
<?php
function searchword($string, $words)
{
$matchFound = count($words);// use tha no of word you want to search
$tempMatch = 0;
foreach ( $words as $word )
{
preg_match('/'.$word.'/',$string,$matches);
//print_r($matches);
if(!empty($matches))
{
$tempMatch++;
}
}
if($tempMatch==$matchFound)
{
return "found";
}
else
{
return "notFound";
}
}
$string = "test check one two test3";
/*** an array of words to highlight ***/
$words = array('test', 'test3');
$string = searchword($string, $words);
echo $string;
?>
If your string is utf-8, you could use preg_replace instead
$string = 'test check one two test3';
$result = preg_replace('/(test3)|(test2)|(test)/ui' , '<$1>' ,$string);
echo $result;
Oviously with this kind of data to match the result will be suboptimal
<test> check one two <test>3
You'll need a longer approach than a direct search and replace with regular expressions (surely if your patterns are prefixes of other patterns)
To begin with, the code you want to enhance does not seem to comply with its initial purpose (not at least in my computer). You can try something like this:
$string = 'test check one two test3';
$result = mb_eregi_replace('(test|test2|test3)', '<\1>', $string);
echo $result;
I've removed the i flag (which of course makes little sense here). Still, you'd still need to make the expression greedy.
As for the original question, here's a little proof of concept:
function replace($match){
$GLOBALS['matches'][] = $match;
return "<$match>";
}
$string = 'test check one two test3';
$matches = array();
$result = mb_eregi_replace('(test|test2|test3)', 'replace(\'\1\')', $string, 'e');
var_dump($result, $matches);
Please note this code is horrible and potentially insecure. I'd honestly go with the preg_replace_callback() solution proposed by Gumbo.