I have a little problem with my function:
function swear_filter($string){
$search = array(
'bad-word',
);
$replace = array(
'****',
);
return preg_replace($search , $replace, $string);
}
It should transform "bad-word" to "**" but the problem is the case sensivity
eg. if the user type "baD-word" it doesn't work.
The values in your $search array are not regular expressions.
First, fix that:
$search = array(
'/bad-word/',
);
Then, you can apply the i flag for case-insensitivity:
$search = array(
'/bad-word/i',
);
You don't need the g flag to match globally (i.e. more than once each) because preg_replace will handle that for you.
However, you could probably do with using the word boundary metacharacter \b to avoid matching your "bad-word" string inside another word. This may have consequences on how you form your list of "bad words".
$search = array(
'/\bbad-word\b/i',
);
Live demo.
If you don't want to pollute $search with these implementation details, then you can do the same thing a bit more programmatically:
$search = array_map(
create_function('$str', 'return "/\b" . preg_quote($str, "/") . "\b/i";'),
$search
);
(I've not used the recent PHP lambda syntax because codepad doesn't support it; look it up if you are interested!)
Live demo.
Update Full code:
function swear_filter($string){
$search = array(
'bad-word',
);
$replace = array(
'****',
);
// regex-ise input
$search = array_map(
create_function('$str', 'return "/\b" . preg_quote($str, "/") . "\b/i";'),
$search
);
return preg_replace($search, $replace, $string);
}
I think you mean
'/bad-word/i',
Do you even need to use regex?
function swear_filter($string){
$search = array(
'bad-word',
);
if (in_array(strtolower($string), $search){
return '****';
}
return $search
}
makes the following assumptions.
1) $string contains characters acceptable in the current local
2) all contents of the $search array are lowercase
edit: 3) Entire string consists of bad word
I suppose this would only work if the string was split and evaluated on a per word basis.
Related
I want to make links using shortcuts following the pattern: controller/#/id. For example: a#3 must be rewritten to /actions/view/3, and t#28 must be a link to /tasks/view/28. I think preg_replace is an "easy" way to achieve this, but I'm not that good with regular expressions and I don't know how to "reuse" the digits from the search-string within the result. I think I need something like this:
$search = array('/a#\d/', '/t#\d/');
$replace = array('/actions/view/$1', '/tasks/view/$1');
$text = preg_replace($search, $replace, $text);
Can someone point me in the right direction?
You can "reuse" the numbers from the search strings using capturing groups, denoted by brackets ().
Try this -
$text = "a#2 a#3 a#5 a#2 t#34 t#34 t#33 t#36";
$search = array('/\ba#(\d+)\b/', '/\bt#(\d+)\b/');
$replace = array('/actions/view/$1', '/tasks/view/$1');
$text = preg_replace($search, $replace, $text);
var_dump($text);
/**
OUTPUT-
string '/actions/view/2 /actions/view/3 /actions/view/5 /actions/view/2 /tasks/view/34 /tasks/view/34 /tasks/view/33 /tasks/view/36' (length=123)
**/
The above answer works, but if you need to add more of those search values, you can store those keys in separate array and you can use preg_replace_callback.This also does the same thing, but now, you only need to add more (alphabets)keys in the array and it will replace it accordingly. Try something like this-
$arr = Array(
"a"=> "/actions/view/",
"t"=> "/tasks/view/"
);
$text = preg_replace_callback("/\b([a-z]+)#(\d+)\b/", function($matches) use($arr){
var_dump($matches);
return $arr[$matches[1]].$matches[2];
},$text);
var_dump($text);
/**
OUTPUT-
string '/actions/view/2 /actions/view/3 /actions/view/5 /actions/view/2 /tasks/view/34 /tasks/view/34 /tasks/view/33 /tasks/view/36' (length=123)
**/
Since the number is not replaced you can use strtr (if it is not too ambigous) :
$trans = array('a#' => '/actions/view/', 't#' => '/tasks/view/');
$text = strtr($text, $trans);
if you can use this, it will be faster than processing a string two times with a regex.
$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.
I'm using a Function to parse UBBC and I want to use a function to find data from a database to replace text (a [user] kind of function). However the code is ignoring the RegExp Variable. Is there any way I can get it to recognise the RegExp variable?
PHP Function:
function parse_ubbc($string){
$string = $string;
$tags = array(
"user" => "#\[user\](.*?)\[/user\]#is"
);
$html = array(
"user" => user_to_display("$1", 0)
);
return preg_replace($tags, $html, $string);
}
My function uses the username of the user to get their display name, 0 denotes that it is the username being used and can be ignored for the sake of this.
Any help would be greatly appreciated.
You either rewrite your code to use preg_replace_callback, as advised.
Or your rewrite the regex to use the #e flag:
function parse_ubbc($string){
$string = $string;
$tags = array(
"user" => "#\[user\](.*?)\[/user\]#ise"
);
$html = array(
"user" => 'user_to_display("$1", 0)'
);
return preg_replace($tags, $html, $string);
}
For that it's important that PHP does not execute the function in the replacement array immediately. That's why you have to put the function call into 'user_to_display("$1", 0)' single quotes. So preg_replace executes it later with the #e flag.
A significant gotcha here is, that the username may never contain " double quotes which would allow the regex placeholder $0 to break up the evaluated function call (cause havoc). Hencewhy you have to rewrite the regex itself to use \w+ instead of .*?. Or again just use preg_replace_callback for safety.
You need to use preg_replace_callback if you want to source replacements from a database.
function parse_ubbc($string){
$string = $string;
function get_user_to_display($m){
user_to_display($m[1], 0);
}
return preg_replace_callback('#\[user\](.*?)\[/user\]#is', 'get_user_to_display', $string);
}
You're calling user_to_display() with the string '$1', not the actual found string. Try:
function parse_ubbc($string){
$string = $string;
$tags = array(
"user" => "#\[user\](.*?)\[/user\]#ise"
);
$html = array(
"user" => 'user_to_display("$1", 0)'
);
return preg_replace($tags, $html, $string);
}
The changes are adding 'e' to the end of the regexp string, and putting the function call in quotes.
I have a question that can I replace a certain character like # with # in a string.
I have all the character checkers and their replacer in an array. Like this--
$string_check = array(
"#" => "#",
.... and so on (list is too big)
);
So how can I do this thing. Please help me out. I only have 20 days of experience with php.
You can feed your translation table right into strtr():
$table = array(
'#' => '...',
);
$result = strtr($source, $table);
str_replace does exactly that and it also accepts arrays as replacement maps:
$string_check = array(
"#" => "#"
);
$result = str_replace (array_keys($string_check), array_values($string_check), $original);
$search = array('hello','foo');
$replace = array('world','bar');
$text = 'hello foo';
$result = str_replace($search,$replace,$text);
// $result will be 'world bar'
but in your case it looks like some kind of encoding, have you tried the htmlspecialchars?
I want want my output like this when I search a keyword like
"programming"
php programming language
How to do this in php mysql?
Any idea?
Just perform a str_replace on the returned text.
$search = 'programming';
// $dbContent = the response from the database
$dbContent = str_replace( $search , '<b>'.$search.'</b>' , $dbContent );
echo $dbContent;
Any instance of "programming", even if as part of a larger word, will be wrapped in <b> tags.
For instances where more than one word are used
$search = 'programming something another';
// $dbContent = the response from the database
$search = explode( ' ' , $search );
function wrapTag($inVal){
return '<b>'.$inVal.'</b>';
}
$replace = array_map( 'wrapTag' , $search );
$dbContent = str_replace( $search , $replace , $dbContent );
echo $dbContent;
This will split the $search into an array at the spaces, and then wrap each match in the <b> tags.
You could use <b> or <strong> tags (See What's the difference between <b> and <strong>, <i> and <em>? for a dicussion about them).
$search = #$_GET['q'];
$trimmed = trim($search);
function highlight($req_field, $trimmed) //$req_field is the field of your table
{
preg_match_all('~\w+~', $trimmed, $m);
if(!$m)
return $req_field;
$re = '~\\b(' . implode('|', $m[0]) . ')\\b~';
return preg_replace($re, '<b>$0</b>', $req_field);
}
print highlight($req_field, $trimmed);
In this way, you can bolden the searched keywords. Its quite easy and works well.
The response is actually a bit more complicated than that. In the common search results use case, there are other factors to consider:
you should take into account uppercase and lowercase (Programming, PROGRAMMING, programming etc);
if your content string is very long, you wouldn't want to return the whole text, but just the searched query and a few words before and after it, for context;
This guy figured it out:
//$h = text
//$n = keywords to find separated by space
//$w = words near keywords to keep
function truncatePreserveWords ($h,$n,$w=5,$tag='b') {
$n = explode(" ",trim(strip_tags($n))); //needles words
$b = explode(" ",trim(strip_tags($h))); //haystack words
$c = array(); //array of words to keep/remove
for ($j=0;$j<count($b);$j++) $c[$j]=false;
for ($i=0;$i<count($b);$i++)
for ($k=0;$k<count($n);$k++)
if (stristr($b[$i],$n[$k])) {
$b[$i]=preg_replace("/".$n[$k]."/i","<$tag>\\0</$tag>",$b[$i]);
for ( $j= max( $i-$w , 0 ) ;$j<min( $i+$w, count($b)); $j++) $c[$j]=true;
}
$o = ""; // reassembly words to keep
for ($j=0;$j<count($b);$j++) if ($c[$j]) $o.=" ".$b[$j]; else $o.=".";
return preg_replace("/\.{3,}/i","...",$o);
}
Works like a charm!