首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-12-05 21:05
  • 2168
  • 7059
juejin.cn

前言

公司产品针对样例中敏感数据的高亮,一直是使用高亮数据字符直接进行匹配的,这样就会有一个问题,比如:某验证码是敏感数据,如果某个数字串之间刚好包含这个验证码的值,那么这区间就会高亮,出现误差。现在需要换成后端返回敏感数据字符的起始下标值,前端计算敏感数据的范围,使高亮数据准确。

image.png

计算字符串中敏感数据在编辑器中的范围

刚接到这个需求,看到这个后端返回的偏移量,笔者以为返回的是在每一行的偏移量,只要算出该敏感数据在编辑器中的每一行就行了。到后面发现后端返回的偏移量是从第一行第一个字符开始,因为,样例原始数据在后端就是一个字符串,没法根据换行符计算在编辑器的哪一行。

没有思路就看看monaco的文档吧,无聊之际,给我发现了一个API:getPositionAt,用于获取给定偏移量的位置,那么后端返回的起始下标就有了用武之地,可以计算出敏感数据的range,直接救了我🐶命!!!兄弟们,还是要好好看文档!

image.png

getPositionAt

  • 语法: getPositionAt(offset: number): IPosition
  • 参数: offset
  • 返回值: IPosition
  • 描述: 用于获取给定偏移量的位置。 offset 参数是一个 number 类型,表示要获取位置的偏移量。

IPosition

ts
代码解读
复制代码
interface IPosition { column: number, lineNumber: number }
  • column

类型: number 只读;默认值: -;可选项: -;描述: 列

  • lineNumber

类型: number 只读;默认值: -‘可选项: -;描述: 行号

  • 根据getPositionAt获取position:
js
代码解读
复制代码
const model = editor.getModel(); const startPosition = model.getPositionAt(valueIndex.startIndex); const endPosition = model.getPositionAt(valueIndex.endIndex); const currentRange = { startLineNumber: startPosition.lineNumber, // 起始位置的行号。 startColumn: startPosition.column, // 起始位置的列号。 endLineNumber: endPosition.lineNumber, // 结束位置的行号。 endColumn: endPosition.column + 1 // 结束位置的列号。 }; editor.setSelection(currentRange);

image.png

根据以上代码,便可以得出该敏感数据在编辑器中的具体范围,再使用setSelection进行选中该范围

getPositionAt存在的问题(位置有偏差)

在自测过程中,发现如果后端返回类型为html、doc时,在编辑器中会自动换行,使用getPositionAt进行计算位置时会有偏差,如下图所示:

image.png

image.png

经过排查发现,这是后端返回的原始内容中只要携带\n就会出现计算位置不准确,比如上面的html、text文本。原本的想法是后端把所有的\n全部去除,但会修改原始内容,直接pass,那么只能由前端重新计算敏感数据的位置。

计算带\n字符串中敏感数据在编辑器中的范围

为了解决这个问题,需要分三步完成操作:

  1. 解析字符串:将字符串按换行符分割成多行,以便精确计算字符的位置。
  2. 计算行列范围:将全局字符偏移量(startIndex 和 endIndex)转换为 Monaco 编辑器中对应的行和列。
  3. 应用高亮:利用 Monaco 的 API 将计算出的范围应用到编辑器中,以实现精准的高亮效果。

实现步骤详解

1. 将字符串分割为行

我们首先需要将原始字符串按照换行符 \n 分割成多个行。这样可以将字符位置从全局偏移量转化为每行的相对偏移量。以下代码展示了如何实现:

js
代码解读
复制代码
const originValue = `'HTTP/1.1 200 OKdate: Thu, 1#################51 GMT\r\nserver: Simple###############/2.7.5\r\ncontent-length: 1#\r\nlast-modified: Wed, 0#################19 GMT\r\ncontent-disposition: attach#############=f.txt\r\ncontent-type: applic############stream\r\n\r\nfile content test!!!!\n 147######12\n'`; // 分割字符串为行 const lines = originValue.split('\n');

将计算方法封装成一个方法函数,具体实现见如下代码,传入索引以及行数组即可得到行号和列号:

js
代码解读
复制代码
/** * 获取行号和列号 * @param {number} index 索引 * @param {string[]} lines 行数组 */ export function getLineAndColumn(index, lines) { let line = 0; // 当前行索引 let column = index; // 当前列索引(初始为字符偏移量) /** * 遍历每一行。lineLength:当前行的长度,加 1 是因为换行符 \n 也占一个字符。 * 判断当前偏移量是否在当前行内: * 如果偏移量小于当前行的长度,则说明目标字符在这一行,返回行号和列号。 * 如果偏移量超过当前行的长度,则减去当前行的长度,更新剩余偏移量,继续检查下一行。 * 如果遍历完所有行,偏移量仍未完全分配,则认为字符在最后一行的某个位置。 */ // 遍历每一行,计算行和列 while (line < lines.length) { const lineLength = lines[line].length + 1; // 每行的字符数(+1 包括换行符) if (column < lineLength) { return { lineNumber: line + 1, column: column + 1 }; // Monaco 编辑器的行、列从 1 开始 } column -= lineLength; // 减去当前行的总长度,更新偏移量 line++; // 检查下一行 } // 如果超出范围,返回最后一行 return { lineNumber: lines.length - 1, column: column }; // 最后一行 }

具体使用(本项目中的数据结构代码,循环因数据结构而异):

js
代码解读
复制代码
const lines = editorContent.split('\n'); const initEditorRangeList = locationObj.data.extractValueDtos?.flatMap( (extractValue) => extractValue.labelValueIndexList?.flatMap((labelValueIndex) => labelValueIndex.valueIndexList.map((valueIndex) => { const startPosition = getLineAndColumn(valueIndex.startIndex,lines); const endPosition = getLineAndColumn(valueIndex.endIndex,lines); return { startLineNumber: startPosition.lineNumber, startColumn: startPosition.column, endLineNumber: endPosition.lineNumber, endColumn: endPosition.column + 1 }; }) ) || [] ) || []; // 仅渲染可见区域内的装饰器,视窗外的内容则延迟加载或忽略。 highlightVisibleRanges(editor, initEditorRangeList);

highlightVisibleRanges方法,请继续阅读下文。使用修改之后的计算位置逻辑,实现精准匹配:

image.png

image.png

优化高亮逻辑

有些样例数据过大,为了避免每次渲染量过大,可能导致该样例内的敏感数据没有高亮,可以使用getVisibleRanges()获取编辑器的可见范围,只渲染编辑器可视范围内的敏感数据,当可视范围发生变化时,再次执行匹配高亮逻辑。优化后的代码如下:

js
代码解读
复制代码
/** * 高亮指定范围内的敏感数据 * @param {*} editor 编辑器实例 * @param {*} rangeList 需要高亮的范围数组 * @param {*} inlineClassName 自定义高亮类名 */ export function highlightVisibleRanges( editor, rangeList, inlineClassName = 'mtk5' ) { function handler() { // 获取编辑器的可见范围 const visibleRanges = editor.getVisibleRanges(); const visibleDecorations = rangeList.filter((range) => { return visibleRanges.some( (visibleRange) => range.startLineNumber >= visibleRange.startLineNumber && range.endLineNumber <= visibleRange.endLineNumber ); }); // 创建装饰器集合,使其高亮 editor.createDecorationsCollection( visibleDecorations.map((range, index) => ({ id: index, range, options: { inlineClassName } })) ); } if (rangeList.length > 0) { // 监听编辑器滚动事件并刷新匹配逻辑 editor.onDidScrollChange(() => { handler(); }); handler(); } }
注:本文转载自juejin.cn的晚风予星的文章"https://juejin.cn/post/7444022992777822260"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

104
前端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top