正则表达式实现关键字高亮

该代码示例展示了如何使用JavaScript和正则表达式在HTML环境中创建一个简单的SQL编辑器,实现关键字(如深蓝色)、数字(如浅绿色)和引号内容(如红色)的高亮显示。通过监听输入框的文本变化,实现实时高亮,并能保持光标位置不变。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用正则表达式实现一个类似于navicat中sql编辑器关键字高亮功能,大致实现以下目标:

  1. 指定关键字高亮(eg. 深蓝色)
  2. 数字高亮(eg. 浅绿色)
  3. 引号内容高亮(eg. 红色)

预期效果如下:
在这里插入图片描述

下面直接上代码,具体解释见代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SQL编辑器</title>
    <style>
		#edit{
			height:100px;
			width:500px;
			border:1px solid red;
			padding: 5px;
			background: black;
			color: white;
			white-space: pre-wrap;
			word-wrap:break-word;
		}
		.hight-light-deepskyblue{
			color: deepskyblue
		}
		.hight-light-red{
			color: red
		}
		.hight-light-lightgreen{
			color: lightgreen
		}
	</style>
</head>
<body>
    <div id="edit" contenteditable>select a.* 
from a 
left join b on a.b_id = b.id 
where a.name like '%杰%' and a.age > 35 and b.type_code = '001'
order by a.name desc</div>
	<script>
		let hljs = (function(){
			//正则替换高亮文本
			function hightLight(el, keywords) {
				const reg = RegExp(`(<)|(>)|(\\b(${keywords.join('|')})\\b)|(\\b(\\d+)\\b)|('[^']*'?|"[^"]*"?)`, 'gi');
				el.innerHTML = el.innerText.replace(reg, (match, k1, k2, k3, k4, k5) => {
				  if (k1) {
					//替换<
					return `&lt;`;
				  } else if (k2) {
					//替换>
					return `&gt;`;
				  } else if (k3) {
					//高亮关键字
					return `<span class='hight-light-deepskyblue'>${match}</span>`;
				  } else if (k5) {
					//高亮数字(作为变量名时不高亮)
					return `<span class='hight-light-lightgreen'>${match}</span>`;
				  } else {
					//高亮引号内容
					return `<span class='hight-light-red'>${match}</span>`;
				  }
				});
			}
			//获取文本长度
			function getNodeTextLength(node) {
			  return node.nodeName === '#text' ? node.length : node.innerText.length;
			}
			//获取光标相对于整个文本的位置
			function getCursorIndex(el, node, index) {
				if(node.previousSibling===null) {
					return node.parentNode===el ? index : getCursorIndex(el, node.parentNode, index);
				}
				return node===el ? index : getCursorIndex(el, node.previousSibling, index + getNodeTextLength(node.previousSibling));
			}
			//根据光标位置(相对于整个文本的位置)获取具体的位置(光标所在元素的位置)
			function getPosition(el, index) {
				if(el.nodeName === '#text') {
					return {el, index};
				}
				let childNodes = el.childNodes;
				for(let i = 0; i<childNodes.length; i++) {
					let node = childNodes[i];
					let length = getNodeTextLength(node);
					if(index <= length) {
						return getPosition(node, index);
					}
					index -= length;
				}
				return {el, index};
			}
			//获取光标位置
			function getSelectionPosition(el, inputType) {
				const selection = window.getSelection();
				let startIndex = 0, endIndex = 0;
				if(selection.rangeCount > 0) {
					const range = selection.getRangeAt(0);
					let {startContainer, endContainer, startOffset, endOffset} = range;
					startIndex = getCursorIndex(el, startContainer, startOffset);
					endIndex = getCursorIndex(el, endContainer, endOffset);
				}
				inputType==='insertParagraph' && (startIndex+=1, endIndex+=1);
				return {startIndex, endIndex};
			}
			//设置光标位置
			function setSelectionPosition(el, startIndex, endIndex) {
				const start = getPosition(el, startIndex), end = getPosition(el, endIndex);
				const selection = window.getSelection();
				const range = document.createRange();
				range.setStart(start.el, start.index);
				range.setEnd(end.el, end.index);
				selection.removeAllRanges();
				selection.addRange(range);
			}
			return {
				autoHightLight: function(el, keywords) {
					//监听输入框文本变化
					el.oninput = function(e) {
						const {target, inputType} = e, {startIndex, endIndex} = getSelectionPosition(target, inputType);
						hightLight(target, keywords);
						setSelectionPosition(target, startIndex, endIndex);
					};
					//初始触发input事件
					el.dispatchEvent(new InputEvent("input"));
				}
			};
		})();
	</script>
    <script>
		const edit = document.getElementById('edit');
		//SQL关键字举例
		const SQL_KEYWORDS = [
			'show', 'case', 'when', 'use', 'alter', 'add', 'change', 'select', 'from', 'as', 'left', 'right', 'inner', 'join', 'on', 'using',
			'where', 'like', 'between', 'and', 'or', 'in', 'not', 'null', 'exists', 'group', 'order', 'by', 'asc', 'desc', 'limit', 'having',
			'union', 'all', 'distinct', 'create', 'truncate', 'drop', 'insert', 'delete', 'update', 'set', 'table', 'count', 'sum', 'max', 'min', 'hvg'
		];
		hljs.autoHightLight(edit, SQL_KEYWORDS);
    </script>
</body>
</html>

实现效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值