Skip to content

Instantly share code, notes, and snippets.

@daidr
Created September 13, 2019 01:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daidr/5d3a6148162228703e62429b7c4dfaef to your computer and use it in GitHub Desktop.
Save daidr/5d3a6148162228703e62429b7c4dfaef to your computer and use it in GitHub Desktop.
用于演示简单的括号匹配算法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>简单的括号匹配算法演示 - By 戴兜</title>
<style>
input {
background: none;
outline: none;
border: 2px black solid;
font-size: 22px;
color: black;
padding: 5px 10px;
}
canvas {
border: 2px black solid;
cursor: not-allowed;
}
button {
outline: none;
background: none;
border: 2px black solid;
font-size: 22px;
color: black;
padding: 3.5px 10px;
transform: translate(-7px, 1px);
cursor: pointer;
}
</style>
</head>
<body>
<h2>括号匹配demo - by 戴兜</h2>
<h3>使用方法</h3>
<p> - 输入需要测试的括号内容,单击绘制,在预览区域点击括号,则会高亮显示对应括号</p>
<h3>限制</h3>
<p> - 最多20字符</p>
<p> - 只匹配英文圆括号</p>
<hr>
<input type="text" id="main-input" style="width:490px" placeholder="在这里输入需要测试的内容" maxlength="20"
value="1234(5)6(7(8))9"></input>
<button id="draw-button">绘制</button>
<br>
<br>
<canvas id="preview-canvas" height="40px"></canvas>
<script>
(function () {
let previewCanvas = document.querySelector("#preview-canvas");
let previewCtx = previewCanvas.getContext("2d");
let canClick, text;
let mainInput = document.querySelector("#main-input");
let drawButton = document.querySelector("#draw-button");
previewCanvas.setAttribute("width", mainInput.offsetWidth + 60);
mainInput.addEventListener("input", function (e) {
canClick = false;
previewCanvas.style.cursor = "not-allowed";
})
previewCanvas.addEventListener("click", function (e) {
if (canClick) {
let count = 10;
let i = 0;
do {
let fontWidth = previewCtx.measureText(text[i])["width"];
count += fontWidth + 10;
i = i + 1;
} while (count - 5 < e.offsetX);
if (i - 1 < text.length) {
let pos = find(text, i - 1);
if (pos != -1) {
draw([i, pos + 1])
} else {
draw([i], [i])
}
}
}
})
drawButton.addEventListener("click", function (e) {
if (validateText(mainInput.value)) {
// 括号匹配
draw();
} else {
// 括号不匹配
drawTip("括号不匹配", "#FF7200", "#fff");
}
})
function drawTip(text, bgColor, fgColor) {
previewCtx.clearRect(0, 0, previewCanvas.width, previewCanvas.height); // 清空绘制
previewCtx.font = "30px 微软雅黑"; // 设置字体样式
previewCtx.fillStyle = bgColor; // 设置填充色
previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); // 绘制tip背景
previewCtx.fillStyle = fgColor; // 设置前景色
previewCtx.fillText(text, 10, 30); // 绘制tip内容
previewCtx.fillStyle = "#000"; // 恢复填充色
canClick = false;
previewCanvas.style.cursor = "not-allowed";
}
function draw(highlight, errorHightlight) {
previewCtx.clearRect(0, 0, previewCanvas.width, previewCanvas.height); // 清空绘制
previewCtx.font = "30px 微软雅黑"; // 设置字体样式
text = mainInput.value; // 赋值全局text
let textLength = text.length; // 取出文本长度
let count = 10; // 字间距初值
for (let i = 0; i < textLength; i++) {
let fontWidth = previewCtx.measureText(text[i])["width"]; // 获取当前字符宽度
if (!errorHightlight && highlight && highlight.indexOf(i + 1) != -1) {
previewCtx.fillStyle = "#DDD6C1"; // 设置填充色
previewCtx.fillRect(count - 5, 0, fontWidth + 10, previewCanvas.height); // 绘制 普通 高亮字符背景
previewCtx.fillStyle = "#000"; // 恢复填充色
}
if (errorHightlight && errorHightlight.indexOf(i + 1) != -1) {
previewCtx.fillStyle = "#FF7200"; // 设置填充色
previewCtx.fillRect(count - 5, 0, fontWidth + 10, previewCanvas.height); // 绘制 错误 高亮字符背景
previewCtx.fillStyle = "#fff"; // 修改前景色
}
previewCtx.fillText(text[i], count, 30); // 绘制字符
count += fontWidth + 10; // 字间距的自增
previewCtx.fillStyle = "#000"; // 恢复填充色
}
canClick = true;
previewCanvas.style.cursor = "pointer";
}
function validateText(str) {
// 快速验证字符串内的括号是否匹配
let stack = [];
let textLength = str.length; // 取出文本长度
for (let i = 0; i < textLength; i++) {
if (!!stack.length && (stack[stack.length - 1] == '(' && str[i] == ')')) {
stack.pop();
} else if (str[i] == '(' || str[i] == ')') {
stack.push(str[i]);
}
}
return !stack.length;
}
function find(str, pos) {
// 寻找对应括号位置
if (str[pos] == "(") {
// 寻找对应右括号
return findR(str, pos);
} else if (str[pos] == ")") {
// 寻找对应左括号
return findL(str, pos);
} else {
return -1;
}
}
function findR(str, pos) {
let nPos = pos + 1;
do {
if (str[nPos] == ")") {
// 直接返回括号位置
return nPos;
} else if (str[nPos] == "(") {
// 递归以跳过子括号位置
nPos = findR(str, nPos) + 1;
} else {
nPos++;
}
} while (nPos < str.length);
return -1;
}
function findL(str, pos) {
let nPos = pos - 1;
do {
if (str[nPos] == "(") {
// 直接返回括号位置
return nPos;
} else if (str[nPos] == ")") {
// 递归以跳过子括号位置
nPos = findL(str, nPos) - 1;
} else {
nPos--;
}
} while (nPos > 0);
return -1;
}
})()
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment