React:突出显示两个索引之间的文本

React: Highlight text between two indexes

因此,对于每个预测,google 放置自动完成 API 也 returns 为每个预测匹配子字符串。

输入:散68

预测:旧金山 68

匹配的子字符串:[{ offset: 0, length: 3 }, { offset: 15, length: 2 }]

预期:San Francisco 68

我的目标是使用匹配的子字符串突出显示部分预测。现在有一些挑战。我可以使用 replace 函数并将每个子字符串替换为 <b>str</b>,但它 returns 是一个字符串,这意味着除非我使用 dangerouslySetInnerHTML,否则此方法不起作用。

我也不认为有办法替换多个子字符串。我尝试使用 reduce 函数,但在第一个循环之后它不会真正起作用,因为索引是错误的。

const highlight = (text, matched_substrings) => {
  return matched_substrings.reduce((acc, cur) => {
    return acc.replace(
      acc.substring(cur.offset, cur.length),
      (str) => `<b>${str}</b>`
    )
  }, text)
}

那么有办法做到这一点吗?我认为 React 使这更复杂。

可能不是最佳解决方案,但绝对可行:) 先决条件是,matched_substrigs 数组必须按偏移量

排序
export const highlightText = (text, matched_substring, start, end) => {
    const highlightTextStart = matched_substring.offset;
    const highlightTextEnd = highlightTextStart + matched_substring.length;

    // The part before matched text
    const beforeText = text.slice(start, highlightTextStart);

    // Matched text
    const highlightedText = text.slice(highlightTextStart, highlightTextEnd);

    // Part after matched text
    // Till the end of text, or till next matched text
    const afterText = text.slice(highlightTextEnd, end || text.length);

    // Return in array of JSX elements
    return [beforeText, <strong>{highlightedText}</strong>, afterText];
};

export const highlight = (text, matched_substrings) => {
    const returnText = [];

    // Just iterate through all matches
    for (let i = 0; i < matched_substrings.length; i++) {
        const startOfNext = matched_substrings[i + 1]?.offset;
        if (i === 0) { // If its first match, we start from first character => start at index 0
            returnText.push(highlightText(text, matched_substrings[i], 0, startOfNext))
        } else { // If its not first match, we start from match.offset 
            returnText.push(highlightText(text, matched_substrings[i], matched_substrings[i].offset, startOfNext))
        }
    }

    return returnText.map((text, i) => <React.Fragment key={i}>{text}</React.Fragment>)
};

如果您不介意使用 dangerouslySetInnerHTML

,这里有一个解决方案
const Highlight = ({ text, substrings }) => {
  const html = substrings.reduce((acc, cur, idx) => {
    return acc.replace(
      new RegExp(
        '(?<=^.{' + (cur.offset + idx * 17) + '})(.{' + cur.length + '})',
      ),
      (str) => `<strong>${str}</strong>`,
    )
  }, text)
  return <span dangerouslySetInnerHTML={{ __html: html }} />
}

这样使用

<Highlight text={...} substrings={...} />