Read the original article:Highlighting Keywords and Consecutive Numbers in Search Results
Context
Issue with highlighting keywords in the prompt word array when displaying search results. Regular matching works for words, but does not properly highlight consecutive numbers (e.g., "1998").
Description
When highlighting search results based on an array of prompt words (e.g., ["you", "good", "1998"]), the following cases should be handled:
- Result: "Hello, please answer 1998" → words "you", "good", and "1998" highlighted in red.
- Result: "You are a good person" → words "you" and "good" highlighted in red.
- Result: "I am your good man" → words "you", "good", and repeated "good" highlighted in red.
- Result: "1998456" → "1998" highlighted in red, while "456" remains black.
The challenge: normal regex-based splitting doesn’t correctly separate numbers like 1998 when they appear inside larger digit sequences.
Solution / Approach
To solve this, a string splitting function with regex handling is implemented. It ensures:
- Chinese characters are matched individually.
- Numbers are matched as consecutive groups.
- Special handling is applied to correctly extract and highlight
1998even when embedded in longer numbers.
Here you can find the related example below;
@Entry
@Component
struct HighlightDemo {
@State bookName: string = 'Hello, please answer 112319981, you are a good person, I am your good man, 1998456';
@State tokenWord: string[] = ["你","好","1998"]
/**
* Split the search result string into an array
*/
splitString(input: string): string[] {
// Match Chinese characters or consecutive numbers
const regex = /[\u4e00-\u9fa5]|\d+/g;
const matches = input.match(regex);
let regNumber = new RegExp('[0-9]+')
matches?.forEach((value: string, index: number) => {
if (regNumber.test(value)) {
if (value.indexOf('1998') == 0) {
matches.splice(index, 1, '1998')
matches.splice(index + 1, 1, value.substring(4, value.length))
} else {
matches.splice(index, 1, value.substring(0, value.indexOf('1998')))
matches.splice(index + 1, 1, '1998')
matches.splice(index + 2, 1, value.substring(value.indexOf('1998') + 4, value.length))
}
}
})
console.log('matches', matches)
return matches || []
}
build() {
Column() {
Text() {
ForEach(this.splitString(this.bookName), (itemStr: string) => {
Span(itemStr)
.attributeModifier(new HighlightModifier(itemStr, this.tokenWord, 13))
.fontWeight(FontWeight.Medium)
})
}
}
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
}
/**
* Keyword highlighting in search results
*/
export class HighlightModifier implements AttributeModifier<SpanAttribute> {
textItem: string = ''
cueWords: string[] = []
fontSize: number = 12
constructor(textItem: string, cueWords: string[], fontSize: number) {
this.textItem = textItem
this.cueWords = cueWords
this.fontSize = fontSize
}
applyNormalAttribute(instance: SpanAttribute): void {
instance.fontColor(
this.cueWords.includes(this.textItem)
? $r('app.color.migu_color_gb_red')
: $r('app.color.migu_color_text_black')
).fontSize(this.fontSize)
}
}
Key Takeaways
- Use regex (
/[\u4e00-\u9fa5]|\d+/g) to split text into meaningful tokens: Chinese characters or numeric groups. - Apply special case handling for substrings like
"1998"within larger numbers. - Use a custom AttributeModifier to highlight only matching tokens with a specific color.
Top comments (0)