highlight the word in the string, if it contains the keyword
Try this:
preg_replace("/\w*?$keyword\w*/i", "<b>$0</b>", $str)
\w*?
matches any word characters before the keyword (as least as possible) and \w*
any word characters after the keyword.
And I recommend you to use preg_quote
to escape the keyword:
preg_replace("/\w*?".preg_quote($keyword)."\w*/i", "<b>$0</b>", $str)
For Unicode support, use the u flag and \p{L}
instead of \w
:
preg_replace("/\p{L}*?".preg_quote($keyword)."\p{L}*/ui", "<b>$0</b>", $str)
highlight multiple keywords in search
regular expressions is the way to go!
function highlight($text, $words) {
preg_match_all('~\w+~', $words, $m);
if(!$m)
return $text;
$re = '~\\b(' . implode('|', $m[0]) . ')\\b~';
return preg_replace($re, '<b>$0</b>', $text);
}
$text = '
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
';
$words = 'ipsum labore';
print highlight($text, $words);
To match in a case-insensitive manner, add 'i' to the regular expression
$re = '~\\b(' . implode('|', $m[0]) . ')\\b~i';
NB: for non-enlish letters like "ä" the results may vary depending on the locale.
Python highlight each word if text contains combination of words
Inside your replacement function, you can do other regex:
import re
text = 'Just for testing, it is fantastic. Lets do it. Cmon'
keywords = ['testing', 'is fantastic']
def highlight(text, keywords):
replacement = lambda match: re.sub(r'([^\s]+)', r'<mark>\1</mark>', match.group())
text = re.sub("|".join(map(re.escape, keywords)), replacement, text, flags=re.I)
print(text)
highlight(text, keywords)
Prints:
Just for <mark>testing</mark>, it <mark>is</mark> <mark>fantastic</mark>. Lets do it. Cmon
Highlight a word if a string contains that word in jinja2
Inside your flask route where you receive the sentence you could replace the word template
with <mark>template</mark>
The HTML element represents text which is marked or highlighted for reference or notation purposes, due to the marked passage's relevance or importance in the enclosing context.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark
Example:
from flask import Flask, render_template
from markupsafe import Markup
app = Flask(__name__)
@app.route("/")
def index():
sentence = "Jinja is a fast, expressive, extensible templating engine. Special placeholders in the template allow writing code similar to Python syntax. Then the template is passed data to render the final document."
data = {"sentence": Markup(sentence.replace("template", "<mark>template</mark>"))}
return render_template("index.html", data=data)
if __name__ == "__main__":
app.run()
You can still add the class to the mark
tag if you want to change the default background-color
.
The same approach can also be done with Javascript:
document.body.innerHTML = document.body.innerHTML.replaceAll(
"template",
"<mark>template</mark>"
);
You could put this somewhere inside some script tags in the template.
In case the DOM hasn't loaded yet and the above doesn't work try:
window.addEventListener("load", function () {
document.body.innerHTML = document.body.innerHTML.replaceAll(
"{{word}}",
"<mark>{{word}}</mark>"
);
});
For more info on this, see this post.
highlight search keywords in text
Use a HTML parser to make sure that you only search through text.
Highlight Specific Word in Associated String and String Variable in Tableau
As I am sure you know, Tableau is going to colour the entire text string as the CONTAINS condition results in TRUE for the entire string. A different approach could be to restructure your data to a 'long' format with 1 row per word (as below).
Doing this will ensure that Tableau knows each word should be evaluated separately and that the Color Marks Card will partition each word. You can then structure your worksheet like this. To ensure the words are showing in the correct order, you'll need a calculated field to create a unique row (I have called sort_order right("000000" + str([sentence_id]),7) + right("000000" + str([Position]), 7)
. Note that the Text Marks Card is sorted by sort_order and also that the order in which you drag on/order the Mark Cards is important
The colour_keyword formula then is simply something like [word] = [Keyword Parameter]
(maybe check for upper/lowercase variants).
I would recommend maintaining your original table's data structure as well as this 'long table format and link the two datasources via a Relationship (Data > Edit Relationships) and use Dashboard Actions. This would hopefully satisfy your highlight requirements and mean less rework for your other worksheets.
I've published the demo tableau workbook to tableau public here
Match and highlight keywords from list in a string
If you have an array of search words:
var searches = new [] { "Match", "matches", "list", "text" };
and a string to search:
var text = "Match all matches from the list in text and highlight the matches";
You can combine the words into a regular expression that searches first or second or third, etc, by combining them with String.Join (The \b
denotes a word boundary so only whole words match):
var regex = @"\b(" + String.Join("|", searches) + @")\b";
// regex: \b(Match|matches|list|text)\b
Then it's a simple matter of applying the search and using a replace to highlight (in a replace expression, $1
is a reference to the first matched group, e.g., the word that was found in the original phrase):
var result = Regex.Replace(text, regex, @"**$1**");
// result: **Match** all **matches** from the **list** in **text** and highlight the **matches**
(Code Demo)
Note that this solution works fine for the example you gave, but there are a number of caveats depending on what your real-world scenario looks like:
- If your search "words" have special characters recognized by Regex, you may have to escape them, e.g.,
\.
,\(
,\)
, etc. - The current code example provided above is case-sensitive, so for example
Match
would not matchmatch
.
Highlight keywords in a paragraph
If it contains html (note that this is a pretty robust solution):
$string = '<p>foo<b>bar</b></p>';
$keyword = 'foo';
$dom = new DomDocument();
$dom->loadHtml($string);
$xpath = new DomXpath($dom);
$elements = $xpath->query('//*[contains(.,"'.$keyword.'")]');
foreach ($elements as $element) {
foreach ($element->childNodes as $child) {
if (!$child instanceof DomText) continue;
$fragment = $dom->createDocumentFragment();
$text = $child->textContent;
$stubs = array();
while (($pos = stripos($text, $keyword)) !== false) {
$fragment->appendChild(new DomText(substr($text, 0, $pos)));
$word = substr($text, $pos, strlen($keyword));
$highlight = $dom->createElement('span');
$highlight->appendChild(new DomText($word));
$highlight->setAttribute('class', 'highlight');
$fragment->appendChild($highlight);
$text = substr($text, $pos + strlen($keyword));
}
if (!empty($text)) $fragment->appendChild(new DomText($text));
$element->replaceChild($fragment, $child);
}
}
$string = $dom->saveXml($dom->getElementsByTagName('body')->item(0)->firstChild);
Results in:
<p><span class="highlight">foo</span><b>bar</b></p>
And with:
$string = '<body><p>foobarbaz<b>bar</b></p></body>';
$keyword = 'bar';
You get (broken onto multiple lines for readability):
<p>foo
<span class="highlight">bar</span>
baz
<b>
<span class="highlight">bar</span>
</b>
</p>
Beware of non-dom solutions (like regex
or str_replace
) since highlighting something like "div" has a tendency of completely destroying your HTML... This will only ever "highlight" strings in the body, never inside of a tag...
Edit Since you want Google style results, here's one way of doing it:
function getKeywordStubs($string, array $keywords, $maxStubSize = 10) {
$dom = new DomDocument();
$dom->loadHtml($string);
$xpath = new DomXpath($dom);
$results = array();
$maxStubHalf = ceil($maxStubSize / 2);
foreach ($keywords as $keyword) {
$elements = $xpath->query('//*[contains(.,"'.$keyword.'")]');
$replace = '<span class="highlight">'.$keyword.'</span>';
foreach ($elements as $element) {
$stub = $element->textContent;
$regex = '#^.*?((\w*\W*){'.
$maxStubHalf.'})('.
preg_quote($keyword, '#').
')((\w*\W*){'.
$maxStubHalf.'}).*?$#ims';
preg_match($regex, $stub, $match);
var_dump($regex, $match);
$stub = preg_replace($regex, '\\1\\3\\4', $stub);
$stub = str_ireplace($keyword, $replace, $stub);
$results[] = $stub;
}
}
$results = array_unique($results);
return $results;
}
Ok, so what that does is return an array of matches with $maxStubSize
words around it (namely up to half that number before, and half after)...
So, given a string:
<p>a whole
<b>bunch of</b> text
<a>here for</a>
us to foo bar baz replace out from this string
<b>bar</b>
</p>
Calling getKeywordStubs($string, array('bar', 'bunch'))
will result in:
array(4) {
[0]=>
string(75) "here for us to foo <span class="highlight">bar</span> baz replace out from "
[3]=>
string(34) "<span class="highlight">bar</span>"
[4]=>
string(62) "a whole <span class="highlight">bunch</span> of text here for "
[7]=>
string(39) "<span class="highlight">bunch</span> of"
}
So, then you could build your result blurb by sorting the list by strlen
and then picking the two longest matches... (assuming php 5.3+):
usort($results, function($str1, $str2) {
return strlen($str2) - strlen($str1);
});
$description = implode('...', array_slice($results, 0, 2));
Which results in:
here for us to foo <span class="highlight">bar</span> baz replace out...a whole <span class="highlight">bunch</span> of text here for
I hope that helps... (I do feel this is a bit... bloated... I'm sure there are better ways to do this, but here's one way)...
Related Topics
How to Define an Empty Object in PHP
PHP Prepend Leading Zero Before Single Digit Number, On-The-Fly
Prevent Nginx 504 Gateway Timeout Using PHP Set_Time_Limit()
How to Explode and Trim Whitespace
Get Woocommerce Product Categories from Wordpress
How to Determine the Memory Footprint (Size) of a Variable
Laravel 4: How to "Order By" Using Eloquent Orm
PHP Array Syntax Parse Error Left Square Bracket "["
Can't Return a Result Set in the Given Context
PHP Share Variable Among Different Users/Sessions
How to Decode This JSON String
Cakephp-3.X: How to Change the Data Type of a Selected Alias
Decode a Quoted Printable Message in PHP
Like Query Using Multiple Keywords from Search Field Using Pdo Prepared Statement
Mysqli_Query() Expects at Least 2 Parameters, 1 Given In