Javascript/react - 高亮匹配括号

时间:2021-07-29 10:20:35

标签: javascript reactjs regex

今天我遇到了在 React 中突出显示匹配括号的问题。这是示例文本:

(my text (is here and) I want (to highlight (something here)))

我希望它在代码编辑器中看起来像,我的意思是: image attached

我尝试使用 react-process-string

processString([
      {
        regex: /\(|\)/g,
        fn: (key, result) => this.colorBracket(key, result[0])
      }
])(value);

colorBracket = (key, result) => {
    const { usedColors } = this.state;

    const bracketColors = ['red', 'green', 'yellow', 'blue', 'purple'];

    let newColor = '';
    if (result === '(') {
      newColor =
        usedColors.length
          ? bracketColors[usedColors.length]
          : bracketColors[0];

      if (!usedColors.includes(newColor)) {
        this.setState({ usedColors: [...usedColors, newColor] });
      }
    } else {
      newColor = usedColors.length
        ? usedColors[usedColors.length - 1]
        : bracketColors[0];

      if (usedColors.length) {
        this.setState({ usedColors: usedColors.filter(e => e !== newColor) });
      }
    }

    return <span style={{ color: newColor }}>{result}</span>;
  };

但我遇到了 react maximum update depth 的问题。

是否可以做得更简单,无需更新状态等?

1 个答案:

答案 0 :(得分:1)

当然,一旦你知道了正确的工具,这并不难。

这是我创建的一个 CodeSandbox example,以及下面相同的片段(针对 Stack Overflow 的古老 Babel 版本稍作调整)。

想法是:

  • 使用 string.split 的正则表达式模式将字符串拆分为括号或不是括号的片段
  • 遍历这些片段以跟踪括号的嵌套级别(以正确着色对)
  • 最后,返回一个带有这些子元素的 React 片段(这样我们就不必处​​理数组键了)

此示例中的颜色只有 3 级深,但您可以轻松添加更多颜色,或使用模数运算符对 N 种颜色进行着色循环。

function BracketHighlighter({ text }) {
  const children = React.useMemo(() => {
    const out = [];
    let level = 0;
    text.split(/([()])/).forEach((bit) => {
      if (bit === "(") {
        level++;
        out.push(<span className={"l" + level}>{bit}</span>);
      } else if (bit === ")") {
        out.push(<span className={"l" + level}>{bit}</span>);
        level--;
      } else {
        out.push(bit);
      }
    });
    return out;
  }, [text]);
  return React.createElement(React.Fragment, {}, ...children);
}

function App() {
  const [text, setText] = React.useState(
    "(my text (is here and) I want (to highlight (something here)))"
  );
  return (
    <div className="App">
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <br />
      <BracketHighlighter text={text} />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
.l1 {
  background-color: orange;
}

.l2 {
  background-color: lightgreen;
}

.l3 {
  background-color: cyan;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>