原文链接:https://blog.csdn.net/mrdeng_web2018/article/details/108426604
近期遇到个问题,需要验证用户输入的字符串中(),小括号是否匹配,是否成对,顺序对不对。
我的需求虽然是只需要考虑到(),是否匹配,但作者把[]、{}也顺带实现了,若果只需要检测某一种括号,将map里的键值对去掉多余的即可,很棒!
我用的是vue项目,所以直接写成工具
bracketMatch.js
// 定义栈的类 class bracketMatchStack { constructor() { this.stack = []; } push(item) { return this.stack.push(item); } pop() { return this.stack.pop(); } // 查询栈顶的元素 peek() { return this.stack[this.getSize() - 1]; } //返回栈的长度 getSize() { return this.stack.length; } // 栈的非空判断 isEmpty() { return this.getSize() === 0; } } export function testBracketIsValid(str) { // 以左右括号来建立一个对象,key为左括号,value为右括号 var Map = { "{": "}", "(": ")", "[": "]", }; //实例化一个栈 const myStack = new bracketMatchStack(); //遍历str字符串 for (let v of str) { if (Map[v]) { myStack.push(v); //是左括号,入栈 } else if (Object.values(Map).includes(v)) { // 右括号 将当前的元素和栈顶的第一个元素进行匹配 let last = myStack.pop(); if (v !== Map[last]) return false; } else { //这里排除的是空字符的情况,如果不是左右括号而是其他的空字符串或者非法字符的话,将终止本次循环,执行下一次循环 continue; } } //遍历完成之后要保证栈内要为空 return myStack.getSize() === 0; }
在项目中使用:
引入
import {testBracketIsValid} from "@/utils/bracketMatch"
使用:
str1 :"(dfsdfsdfsd)dasdadas()(())", str2:"(dgdfdgfd(fgdgfd)", str3 :"(dfsdfsdfsd)dasdadas()(({}))", str4:"[dgdfdgfdfgdgfd]", str5:")(", str6:"()(",
console.log(testBracketIsValid(this.str1));//true console.log(testBracketIsValid(this.str2));//false console.log(testBracketIsValid(this.str3));//true console.log(testBracketIsValid(this.str4));//true console.log(testBracketIsValid(this.str5));//false console.log(testBracketIsValid(this.str6));//false
总结:
很多人说用了栈的先进后出特点,但是我觉得对于一个纯前端来说,一直就用js,说栈显的有点深奥,对新手不友好,(先进后出,我觉得是很正常的,还原理什么,有点深奥,相信一直使用js的人,不需要去解释这一点,这一切都很自然,不需要用栈来解释)。
压栈其实就是数组的push方法(想数组最后添加元素),弹出栈,就是pop方法(去除数组内的最后一位元素)。
用for of遍历字符串,遇见左括号就将左括号push进去(说栈也可以说数组也行)。遇到右括号,就将数组最后的左括号pop出去(弹出);如果当前的右括号与弹出的括号不是一个类型则返回false,这可以确定,括号的匹配有问题了,就返回false。如果遇到不是括号的元素直接结束本次循环,继续下一次循环(continue)。最后,看看数组内是否清除干净,如果不干净,数组长度部位0,代表括号不是成对出现的,是奇数,返回false。这样就可以检验括号是否成对出现以及匹配是否正确,感谢作者的文章,让我拓宽点小技能。
===============================
改成自己所需要的的插件:
需求:
1、我只需要检查()小括号是否成对出现,出现位置是否合法即可,不需要验证{}、[]。
2、我需要知道最外层小括号的内容
思路:以上不合法是返回true、false,我想让合法时,返回最外层小括号内的内容,最外层小括号可能有无限个,当合法时我返回一个数组,里存放着所有最外层小括号的内容,不合法时依然返回false。
怎么判断是最外层小括号呢?
当压栈后,数组长度为1时,此时的小括号就是最外层左小括号。记录索引
弹栈前,数组长度为1时,此时是最外层右小括号。记录索引。然后截取中间的内容,就是最外层小括号的内容,之后将这些信息存到一个对象里,push到盛放最外层小括号内容的数组内。
验证成功后将这个数组返回出去。
具体代码实现:
bracketMatch.js
// 定义栈的类 class bracketMatchStack { constructor() { this.stack = []; } push(item) { return this.stack.push(item); } pop() { return this.stack.pop(); } // 查询栈顶的元素 peek() { return this.stack[this.getSize() - 1]; } //返回栈的长度 getSize() { return this.stack.length; } // 栈的非空判断 isEmpty() { return this.getSize() === 0; } } export function testBracketIsValid(str) { // 以左右括号来建立一个对象,key为左括号,value为右括号 var Map = { "(": ")", }; var outerMostBracketValue = [];//最外层括号的内容 //实例化一个栈 const myStack = new bracketMatchStack(); //遍历str字符串 var start = 0;//用来记录最外层左括号的索引 只有最外层左括号时这个值才会变 for (let index = 0; index < str.length;index++) { let v = str[index]; if (Map[v]) { myStack.push(v); //是左括号,入栈 if(myStack.getSize() == 1){//第一个左括号就是最外层 start = index;//最外层左括号的索引 } } else if (Object.values(Map).includes(v)) { // 右括号 将当前的元素和栈顶的第一个元素进行匹配 if(myStack.getSize() == 1){//最外层右括号时 let o = { start:start,//最外层左括号索引 end:index,//最外层右括号索引 value:str.substring(start,index + 1),//最外层括号的值 } outerMostBracketValue.push(o); } let last = myStack.pop(); if (v !== Map[last]) return false; } else { //这里排除的是空字符的情况,如果不是左右括号而是其他的空字符串或者非法字符的话,将终止本次循环,执行下一次循环 continue; } } //遍历完成之后要保证栈内要为空 if(myStack.getSize() === 0){ return outerMostBracketValue; }else { return false; } }
使用:
data(){ return{ str1 :"(dfsdfsdfsd)dasdadas()(())", str2:"(dgdfdgfd(fgdgfd)", str3 :"(dfsdfsdfsd)dasdadas()(({}))", str4:"[dgdfdgfdfgdgfd]", str5:")(", str6:"()(", } }, mounted(){ console.log(testBracketIsValid(this.str1)); console.log(testBracketIsValid(this.str2)); console.log(testBracketIsValid(this.str3)); console.log(testBracketIsValid(this.str4)); console.log(testBracketIsValid(this.str5)); console.log(testBracketIsValid(this.str6)); }
结果:
。