Выделение текста пользовательскими цветами на основе многих регулярных выражений

После нескольких попыток у меня есть рабочее решение с Highlight реактивный компонент. Я не уверен, что алгоритм очень чист или эффективен, особенно когда речь идет о сохранении необязательного цвета рядом с совпадениями.

В принципе, mark реквизит { color: string, rule: string } с правилом, являющимся допустимым регулярным выражением или массивом указанного типа.

import { memo, useMemo } from 'react'

export function Highlight({ mark, children, ...props }) {
    const highlights = useMemo(() => highlight(children, mark), [children, mark])

    return <span {...props}>{ highlights }</span>
}

function highlight(text, mark) {
    const marks = Array.isArray(mark) ? mark : [mark]
    const matches = marks
        .flatMap(mark => [...text.matchAll(mark.rule ?? mark)].map(match => ({ color: mark.color, match })))
        .filter(({ match }) => match && match.length)
        .sort(({ match }) => match.index)

    let index = 0
    let highlights = []
    for (let { match, color } of matches) {
        highlights.push(text.slice(index, match.index))
        highlights.push(<mark className={color}>{ match[0] }</mark>)

        index = match.index + match[0].length
    }
    if (index < text.length)
        highlights.push(text.slice(index))

    return highlights
}

export default memo(Highlight)

Я знаю, что этот способ ведения дел не обрабатывает перекрывающиеся совпадения, но я даже не знаю, с чего начать.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *