Created
September 13, 2019 01:46
-
-
Save daidr/5d3a6148162228703e62429b7c4dfaef to your computer and use it in GitHub Desktop.
用于演示简单的括号匹配算法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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