BFE.dev is like a LeetCode for Front End developers. I’m using it to practice my skills.
This article is about the coding problem BFE.dev#55. highlight keywords in HTML string
Analysis
The goal is to wrap keywords with <em>.
highlightKeywords(
'Hello FrontEnd Lovers',
['Hello', 'Front', 'JavaScript']
)
// '<em>Hello</em> <em>Front</em>End Lovers'
Looks easy, just search for the keywords and replace them. But it is trickier when there are overlapping keywords
highlightKeywords(
'Hello FrontEnd Lovers',
['Front', 'FrontEnd', 'JavaScript']
)
// 'Hello <em>FrontEnd</em> Lovers'
The idea I came up is like this.
- when we find a keyword, say
'Front'in above example, we keep track of thestartandend. - we loop through the letters between them, and check if there is new word matched. If matched we extend the
endif needed, this is in case there are some keywords likeontE. - stop when
endis met. The substring betweenstartandendshould be highlighted.
Above logic handles overlapping, what about adjacent case ?
highlightKeywords(
'Hello FrontEnd Lovers',
['Front', 'End', 'JavaScript']
)
// 'Hello <em>FrontEnd</em> Lovers'
For this case, we could actually repeatedly search for the intervals from above logic, and group them up.
Show me the code
First we solve a sub problem:
Given a start index, return the end index of highlighting substring.
If not found, return -1.
We could follow the steps explained above to get the following code.
const keywordSet = new Set(keywords)
// return -1 if non-existing
const getEndForEm = (start) => {
let isEmFound = false
let end = start
// extend end if new keywords are matched.
while (start <= end) {
for (let word of keywordSet) {
const length = word.length
if (html.slice(start, start + length) === word) {
isEmFound = true
end = Math.max(end, start + length - 1)
}
}
start += 1
}
return isEmFound ? end : -1
}
Now things become easier, we could just loop through all the indexes, and repeatedly call above function to get the real end index to highlight.
let result = ''
for (let i = 0; i < html.length;) {
let endForEm = getEndForEm(i)
// check if there is adjacent keyword
while (endForEm > -1) {
const nextEndForEm = getEndForEm(endForEm + 1)
if (nextEndForEm === -1) {
break
}
endForEm = nextEndForEm
}
if (endForEm > -1) {
result += '<em>' + html.slice(i, endForEm + 1) + '</em>'
i = endForEm + 1
} else {
result += html[i]
i += 1
}
}
return result
Passed
This is an interesting problem.
Hope it helps, you can have a try at here


Top comments (0)