I'm having some issues with searching a string in long text. I want to extract only searched text and bold searched text with maybe 10-20 characters before it and after searched characters.
So basically what I want to achieve is, ex. from that text:
Hi there, I want to achieve a new goal to create a good search bar for my app. It should be just as any other search bar.
So if I want to search "good search", it should return something like:
...achieve a new goal to create a good search bar for my app. It should be just...
What would be a best way to do it? I tried something like:
const text = "Hi there, I want to achieve a new goal to create a good search bar for my app. It should be just as any other search bar."
const search_text = "good search"
const radius = 10;
// To determine where is the first character
const find_first = text.search(search_text)
const search_from = find_first - radius;
// To ensure that we are taking from first with length of searched text and additional ones
const search_to = find_first + search_text.length + radius
But still, this is only to determine how to check which characters to get. But how to list them and show with highlight?
const text = "Hi there, I want to achieve a new goal to create a good search bar for my app. It should be just as any other search bar."
const search_text = "good search"
const RADIUS = 20;
const indexPosition = text.search(search_text)
const startPosition = indexPosition - RADIUS
const endPosition = indexPosition + RADIUS + search_text.length
const searchResult = (`...${text.slice(startPosition, endPosition)}...`).replace(search_text, `<b>${search_text}</b>`)
console.log({searchResult})
and then you can apply your highlight with the way you like,(I add <b> tag around search text, I assume u want it as HTML format)
The following snippet avoids breaking up words by taking up to 5 word-blank combinations (((?:\\S+\\s+){0,5})) before the search pattern pat and up to 5 blank-word combinations after the search pattern
to create the formatted string result:
const inp = document.querySelector("input"),
findPat = () => {
let html, pat = inp.value.trim();
if (pat.length) {
const rx = new RegExp(`(?<=((?:\\S+\\s+){0,5}))\\b(${pat})\\b(?=((?:\\s+\\S+){0,5}))`, "ig");
html = [...document.querySelectorAll("#content p")].reduce((a, p) => {
let fnd = [...p.textContent.matchAll(rx)];
if (fnd.length) a.push(fnd);
return a;
}, []).flat().map(([_, pre, txt, post]) =>
`<p>...${pre}<b>${txt}</b>${post}...`
).join("");
} else html = "";
document.querySelector("#result").innerHTML = html
};
inp.addEventListener("input", findPat); // assign the event function to the "input" event
findPat(); // run the event function with the initial value of inp
<div id="content">
<p>Here we find some random text. It should fill the page but not attract any unnecessary attention to itself if it is done in a good way.</p>
<p>In a second good paragraph I will hide the text that is of interest here: "Hi there, I want to achieve a new goal to create a good search bar for my good app. It should be just as any other search bar." Just to give it a bit more body this last sentence was also added.</p>
</div>
<input type="text" value="good"></input>
<hr>
<div id="result" value="good"></div>
The positive lookbehind ((?<=((?:\\S+\\s+){0,5}))) and lookahead (?=((?:\\s+\\S+){0,5})) around the search pattern (\\b(${pat})\\b -> the \\b look for a word boundary) are necessary for allowing fully overlapping result strings. The second "good" in: "... to create a good search bar in my good app." could not be matched otherwise.
For simplicity I used <b>...</b> to format the text matching the search pattern bold. This can, of course, be replaced by anything else like <span class="hilight">...</span>.
The new RegExp() expression will probably also need some further attention: should there be "special characters" (like a dot: . or a question mark ?) in the search pattern pat and these are to be found as such, they will need to be masked (by a preceding \\) as otherwise they will be misinterpreted as being part of a regular expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With