如何利用正则表达式和 CSS 在 CodeMirror 中高亮日志字段?

如何利用正则表达式和 CSS 在 CodeMirror 中高亮日志字段?
最新回答
夜久泪长

2023-09-13 11:07:42

在 CodeMirror 中利用陵明正则表达式和 CSS 高亮日志字段,需结合正则匹配、DOM 操作和样式定义戚汪袜。以下是具体实现步骤:

1. 定义正则表达式匹配日志字段

根据日志格式编写正则表达式,例如匹配 User [用户名] logged in 结构:

const regex = /User (w+) logged in/g; // w+ 匹配用户名(字母、数字、下划线)
  • 关键点:正则需包含捕获组(如 (w+))以便提取字段,或直接匹配完整模式(如 User w+ logged in)。
2. 通过 CodeMirror API 获取或操作内容

CodeMirror 提供了 getValue() 和 replaceRange() 等方法操作高激编辑器内容。若需动态高亮,需监听内容变化或手动触发高亮逻辑:

// 示例:获取编辑器内容并匹配const editor = CodeMirror.fromTextArea(document.getElementById('editor'), { mode: 'text/plain', // 根据日志类型选择模式(如 'javascript') lineNumbers: true});function highlightLogFields() { const logContent = editor.getValue(); const highlighted = logContent.replace(regex, `<span class="highlight">$&</span>`); // 注意:直接替换文本会破坏 CodeMirror 的结构,需通过标记(Marker)或装饰(Decoration)实现}
  • 问题:直接替换文本会丢失 CodeMirror 的语法分析功能,推荐使用官方提供的装饰 API。
3. 使用 CodeMirror 装饰(Decoration)实现高亮

CodeMirror 6 提供了 Decoration 和 WidgetType 实现无侵入式高亮:

import { basicSetup, EditorView } from "codemirror";import { javascript } from "@codemirror/lang-javascript";import { Decoration, ViewPlugin, WidgetType } from "@codemirror/view";class HighlightWidget extends WidgetType { constructor(readonly text) { super(); } eq(other) { return other.text === this.text; } toDOM() { const span = document.createElement("span"); span.className = "highlight"; span.textContent = this.text; return span; }}function highlightPlugin(view) { const text = view.state.doc.toString(); const matches = []; let match; while ((match = regex.exec(text)) !== null) { matches.push({ from: match.index, to: regex.lastIndex, text: match[0] // 匹配的完整文本 }); regex.lastIndex = match.index + 1; // 避免重叠匹配 } const decorations = Decoration.set( matches.map(match => Decoration.widget({ widget: new HighlightWidget(match.text), side: 0 }).range(match.from) ) ); return ViewPlugin.fromClass(class { decorations = decorations; update(update) { if (update.docChanged) { this.decorations = highlightPlugin(view).decorations; } } }, { decorations: v => v.decorations });}new EditorView({ doc: "User admin logged in at 2023-01-01nUser guest logged in", extensions: [basicSetup, javascript(), highlightPlugin], parent: document.body});
  • 关键点

    自定义 WidgetType 包裹匹配文本并应用 CSS 类。

    通过 ViewPlugin 动态更新装饰,响应内容变化。

4. CSS 样式定义

在全局或编辑器容器中定义高亮样式:

.highlight { background-color: yellow; font-weight: bold; padding: 0 2px; border-radius: 2px;}
  • 扩展性:可针对不同日志字段定义不同类名(如 .highlight-error、.highlight-user)。
5. 优化与注意事项
  • 性能:频繁的正则匹配可能影响性能,建议在内容变化后延迟执行(如 setTimeout 或 requestIdleCallback)。
  • 正则准确性:确保正则表达式覆盖所有变体(如用户名包含特殊字符时使用 [w-]+)。
  • CodeMirror 版本

    CodeMirror 5 使用 lineWidgets 或 markText:editor.on("change", () => { const text = editor.getValue(); const matches = []; let match; while ((match = regex.exec(text)) !== null) { matches.push({ from: editor.posFromIndex(match.index), to: editor.posFromIndex(regex.lastIndex) }); regex.lastIndex = match.index + 1; } // 清除旧标记并添加新标记 editor.getAllMarks().forEach(mark => mark.clear()); matches.forEach(match => { editor.markText(match.from, match.to, { className: "highlight" }); });});

    CodeMirror 6 推荐使用 Decoration(如上示例)。

完整示例(CodeMirror 6)<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>CodeMirror 日志高亮</title> <style> .highlight { background-color: yellow; } </style> <link rel="stylesheet" href="
https://unpkg.com/@codemirror/basic-setup@latest/dist/basic-setup.css"></head><body>
<div id="editor"></div> <script src="
https://unpkg.com/@codemirror/basic-setup@latest/dist/index.js"></script>
<script src="
https://unpkg.com/@codemirror/lang-javascript@latest/dist/index.js"></script>
<script src="
https://unpkg.com/@codemirror/view@latest/dist/index.js"></script>
<script> const { basicSetup, EditorView } = CM; const { javascript } = CM.language; const { Decoration, ViewPlugin, WidgetType } = CM.view; const regex = /User (w+) logged in/g; class HighlightWidget extends WidgetType { constructor(text) { super(); this.text = text; } eq(other) { return other.text === this.text; } toDOM() { const span = document.createElement("span"); span.className = "highlight"; span.textContent = this.text; return span; } } function highlightPlugin(view) { const text = view.state.doc.toString(); const matches = []; let match; while ((match = regex.exec(text)) !== null) { matches.push({ from: match.index, to: regex.lastIndex, text: match[0] }); } regex.lastIndex = 0; // 重置正则索引 const decorations = Decoration.set( matches.map(match => Decoration.widget({ widget: new HighlightWidget(match.text), side: 0 }).range(match.from) ) ); return ViewPlugin.fromClass(class { decorations = decorations; update(update) { if (update.docChanged) { this.decorations = highlightPlugin(view).decorations; } } }, { decorations: v => v.decorations }); } new EditorView({ doc: "User admin logged innError: Failed to log innUser guest logged in", extensions: [basicSetup, javascript(), highlightPlugin], parent: document.getElementById("editor") }); </script></body></html>

通过上述方法,可实现动态、高效且可维护的日志字段高亮功能。