I am successfully highlighting the results but the problem I'm facing is that the code is duplicating the results. For instance, even when I have just one occurrence of "this random text", the code inserts duplicate results inside the excerpt in a strange way. Stuck here, please help. I have attached a screenshot to help understand the issue. You can also see from my text that the sentence now doesn't make sense because it's not finding and truncating properly so that only the paragraph containing the matching keyword appears.
function wps_highlight_results($text){
if(is_search()){
$sr = get_query_var('s');
$keys = explode(" ",$sr);
$text = preg_replace('/('.implode('|', $keys) .')/iu', '<strong class="search-excerpt">'.$sr.'</strong>', $text);
}
return $text;
}
add_filter('the_excerpt', 'wps_highlight_results');
Assuming you want to replace all instances of the search string (e.g. in the beginning) with <strong class="search-excerpt">in the beginning</strong> then you'll need to change your code:
$text = preg_replace(
preg_quote("/$sr/iu"),
'<strong class="search-excerpt">'.$sr.'</strong>',
$text
);
I've added the call to preg_quote() to make sure any regexp chars that might be in $sr are properly escaped.
Related
currently working on a following function:
public function boldText($searchSuggestions)
{
$search = $this->getRequestParameter('search');
$pattern = "/".$search."/u";
$searchSuggestions = preg_replace($pattern, '<b>'.$search.'</b>', $searchSuggestions);
echo $searchSuggestions;
}
Let's say $searchSuggestions = hello
While the user is typing in the search box, which in this case the variable $search contains this input, a dropdown menu of all possible result suggestions are displayed. If a user types 'hello', then the search results like 'helloworld' or 'hello2' would pop up and the inputted word, int this case 'hello' would be bold in all outputted search results. So far it is working fine, however, big Characters are being replaced with small Characters and vice versa in the outputted search results. I have a feeling that the underlying problem might be in this function, however I am not entirely sure. If anyone has any suggestions or tips on where to look, it would be great!
If I should give out more info please do let me know, and I will edit the question immediately.
Thankyou!
Example output currently -
User types in search bar - 'hello'
result shown should be - 'Hello'
result actually being shown - 'hello'
P.S The results are accessed from an sql query. If a user types, than a query that gets data related to the words inputted is shown. For instance - 'SELECT * FROM test WHERE example LIKE '%hello%'
In database one can find the word Hello. Note the H has a big character.
I tried this following code
public function boldText($searchSuggestions)
{
$search = $this->getRequestParameter('search');
$pattern = "/".$search."/u";
$searchSuggestions = preg_replace($pattern, '<b>'.$search.'</b>', $searchSuggestions);
echo $searchSuggestions;
}
Brief Explanation
$searchSuggestions
Hello
$search(being typed by the user)
h
The output should be
<b>H</b>ello
The output I am currently getting is
<b>h</b>ello
I tried to look further on how to properly solve this and it was a bit simpler than I expected. Did not have to use preg_replace for this. The following code did the trick for me:
public function boldText($searchSuggestions)
{
$search = $this->getRequestParameter('search');
$lastPosition = strlen($search);
$firstPosition = stripos($searchSuggestions, $search);
$replacement = substr($searchSuggestions, $firstPosition, $lastPosition);
$searchSuggestions = substr_replace($searchSuggestions, '<b><u>'.$replacement.'</u></b>', $firstPosition, $lastPosition);
echo $searchSuggestions;
}
$lastPosition - we find how long the search input is, therfore getting the last position
$firstPosition - compare the two strings by finding a match(case insensitive), therefore finding the first position
$replacement - we remove what matches between search and searchSuggestion from the searchSuggestion string, with the help of the firstPosition and lastPosition variables.
At the end the searchSuggestion variable is replaced accordingly. Hope I was clear enough if not please let me know. (Answered my own question lol!)
You need to capture the found text you then can use that in the replacement bit. Your current implementation uses the input which may or may not match the case of the original string. So you should:
use the i modifier so your search is case insensitive
use word boundaries so partial matching doesn't occur
use capture group to capture the match
use preg_quote so any special regex characters don't affect regex operations
public function boldText($searchSuggestions)
{
$search = $this->getRequestParameter('search');
$pattern = "/\b(". preg_quote($search) . ")\b/iu";
$searchSuggestions = preg_replace($pattern, '<b>$1</b>', $searchSuggestions);
echo $searchSuggestions;
}
If partial word matching is intended you can remove word boundaries:
public function boldText($searchSuggestions)
{
$search = $this->getRequestParameter('search');
$pattern = "/(". preg_quote($search) . ")/iu";
$searchSuggestions = preg_replace($pattern, '<b>$1</b>', $searchSuggestions);
echo $searchSuggestions;
}
consider https://en.wikipedia.org/wiki/Scunthorpe_problem#Origin_and_history also though.
So I need to re-write some old code that I found on a library.
$text = preg_replace("/(<\/?)(\w+)([^>]*>)/e",
"'\\1'.strtolower('\\2').'\\3'", $text);
$text = preg_replace("/<br[ \/]*>\s*/","\n",$text);
$text = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n",
$text);
And for the first one I have tried like this:
$text = preg_replace_callback(
"/(<\/?)(\w+)([^>]*>)/",
function($subs) {
return strtolower($subs[0]);
},
$text);
I'm a bit confused b/c I don't understand this part: "'\\1'.strtolower('\\2').'\\3'" so I'm not sure what should I replace it with.
As far as I understand the first line looks for tags, and makes them lowercase in case I have data like
<B>FOO</B>
Can you guys help me out here with a clarification, and If my code is done properly?
The $subs is an array that contains the whole value in the first item and captured texts in the subsequent items. So, Group 1 is in $subs[1], Group 2 value is in $subs[2], etc. The $subs[0] contains the whole match value, and you applied strtolower to it, but the original code left the Group 3 value (captured with ([^>]*>) that may also contain uppercase letters) intact.
Use
$text = preg_replace_callback("~(</?)(\w+)([^>]*>)~", function($subs) {
return $subs[1] . strtolower($subs[2]) . $subs[3];
}, $text);
See the PHP demo.
I have a string of words in an array, and I am using preg_replace to make each word into a link. Currently my code works, and each word is transformed into a link.
Here is my code:
$keywords = "shoes,hats,blue curtains,red curtains,tables,kitchen tables";
$template = '%1$s';
$newkeys = preg_replace("/(?!(?:[^<]+>|[^>]+<\/a>))\b([a-z]+)\b/is", sprintf($template, "\\1"), $keywords);
Now, the only problem is that when I want 2 or 3 words to be a single link. For example, I have a keyword "blue curtains". The script would create a link for the word "blue" and "curtains" separately. I have the keywords separated by commas, and I would like the preg_replace to only replace the text between the commas.
I've tried playing around with the pattern, but I just can't figure out what the pattern would be.
Just to clarify, currently the output looks as follows:
shoes,hats,blue curtains,red curtains,tables,kitchen tables
While I want to achieve the following output:
shoes,hats,blue curtains,red curtains,tables,kitchen tables
A little bit change in preg_replace code and your job will done :-
$keywords = "shoes,hats,blue curtains,red curtains,tables,kitchen tables";
$template = '%1$s';
$newkeys = preg_replace("/(?!(?:[^<]+>|[^>]+<\/a>))\b([a-z ' ']+)\b/is", sprintf($template, "\\1"), $keywords);
OR
$newkeys = preg_replace("/(?!(?:[^<]+>|[^>]+<\/a>))\b([a-z' ']+)\b/is", sprintf($template, "\\1"), $keywords);
echo $newkeys;
Output:- http://prntscr.com/77tkyb
Note:- I just added an white-space in your preg_replace. And you can easily get where it is. I hope i am clear.
Matching white-space along with words is missing there in preg_replace and i added that only.
im trying to create a system where a user can type in a phrase into a rich text editor such as '{item(5)}', then when the code renders the content on a page in the front end the '{item(5)}' is replaced with a snippet of code / function that uses the 5 as an unique identifier
I guess similar to how a wordpress widget would work,
im not to familiar using preg_ functions but have managed to pull out the {item(5)} and replace with a function, however the problem is it removes the rest of the content.
i might not be not be on the right lines but here is the code so far, any help would be most appreciated
$string ='This is my body of text, you should all check out this item {item(7)} or even this item {item(21)} they are great...';
if(preg_match_all('#{item((?:.*?))}#is', $string, $output, PREG_PATTERN_ORDER))
$matches = $output[0];
foreach($matches as $match){
item_widget(preg_replace("/[^0-9]/", '', $match));
}
The item_widget is just a function that uses the number to bring out a html chunk
You probably want a preg_replace_callback instead:
$output = preg_replace_callback('/\{item\((\d+)\)\}/', function($match) {
// item_widget should *return* its result for you to insert into your stream
return item_widget($match[1]);
}, $string);
This will replace the {item(n)} markers with the relevant widget results, assuming - as mentioned in the code comment - that it actually returns its code.
This works for me:
{item\(([\d]+)\)}
Checkout this eval.
so there are two parts for this question. First of all, you need to write a tag extracting part and then substitution part:
<?php
$in = "foo bar {item(1)} {item(2)}";
$out = $in;
if ($m = preg_match_all("/({item\([0-9]+\)})/is",$in,$matches)){
foreach ($matches[1] as $match){
preg_match("/\(([0-9]+)\)/", $match, $t);
$id = $t[1];
/* now we have id, do the substitution */
$out = preg_replace("/".preg_quote($match) . "/", "foo($id)", $out);
}
}
now $out should have the replaced string.
This function searches for words (from the $words array) inside a text and highlights them.
function highlightWords(Array $words, $text){ // Loop through array of words
foreach($words as $word){ // Highlight word inside original text
$text = str_replace($word, '<span class="highlighted">' . $word . '</span>', $text);
}
return $text; // Return modified text
}
Here is the problem:
Lets say the $words = array("car", "drive");
Is there a way for the function to highlight not only the word car, but also words which contain the letters "car" like: cars, carmania, etc.
Thank you!
What you want is a regular expression, preg_replace or peg_replace_callback more in particular (callback in your case would be recommended)
<?php
$searchString = "The car is driving in the carpark, he's not holding to the right lane.\n";
// define your word list
$toHighlight = array("car","lane");
Because you need a regular expression to search your words and you might want or need variation or changes over time, it's bad practice to hard code it into your search words. Hence it's best to walk over the array with array_map and transform the searchword into the proper regular expression (here just enclosing it with / and adding the "accept everything until punctuation" expression)
$searchFor = array_map('addRegEx',$toHighlight);
// add the regEx to each word, this way you can adapt it without having to correct it everywhere
function addRegEx($word){
return "/" . $word . '[^ ,\,,.,?,\.]*/';
}
Next you wish to replace the word you found with your highlighted version, which means you need a dynamic change: use preg_replace_callback instead of regular preg_replace so that it calls a function for every match it find and uses it to generate the proper result. Here we enclose the found word in its span tags
function highlight($word){
return "<span class='highlight'>$word[0]</span>";
}
$result = preg_replace_callback($searchFor,'highlight',$searchString);
print $result;
yields
The <span class='highlight'>car</span> is driving in the <span class='highlight'>carpark</span>, he's not holding to the right <span class='highlight'>lane</span>.
So just paste these code fragments after the other to get the working code, obviously. ;)
edit: the complete code below was altered a bit = placed in routines for easy use by original requester. + case insensitivity
complete code:
<?php
$searchString = "The car is driving in the carpark, he's not holding to the right lane.\n";
$toHighlight = array("car","lane");
$result = customHighlights($searchString,$toHighlight);
print $result;
// add the regEx to each word, this way you can adapt it without having to correct it everywhere
function addRegEx($word){
return "/" . $word . '[^ ,\,,.,?,\.]*/i';
}
function highlight($word){
return "<span class='highlight'>$word[0]</span>";
}
function customHighlights($searchString,$toHighlight){
// define your word list
$searchFor = array_map('addRegEx',$toHighlight);
$result = preg_replace_callback($searchFor,'highlight',$searchString);
return $result;
}
I haven't tested it, but I think this should do it:-
$text = preg_replace('/\W((^\W)?$word(^\W)?)\W/', '<span class="highlighted">' . $1 . '</span>', $text);
This looks for the string inside a complete bounded word and then puts the span around the whole lot using preg_replace and regular expressions.
function replace($format, $string, array $words)
{
foreach ($words as $word) {
$string = \preg_replace(
sprintf('#\b(?<string>[^\s]*%s[^\s]*)\b#i', \preg_quote($word, '#')),
\sprintf($format, '$1'), $string);
}
return $string;
}
// courtesy of http://slipsum.com/#.T8PmfdVuBcE
$string = "Now that we know who you are, I know who I am. I'm not a mistake! It
all makes sense! In a comic, you know how you can tell who the arch-villain's
going to be? He's the exact opposite of the hero. And most times they're friends,
like you and me! I should've known way back when... You know why, David? Because
of the kids. They called me Mr Glass.";
echo \replace('<span class="red">%s</span>', $string, [
'mistake',
'villain',
'when',
'Mr Glass',
]);
Sine it's using an sprintf format for the surrounding string, you can change your replacement accordingly.
Excuse the 5.4 syntax