正则表达式可视化工具

前端之家收集整理的这篇文章主要介绍了正则表达式可视化工具前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Index.html

<html>
    <head>
        <title>正则表达式图形化工具</title>
        <link rel="stylesheet" type="text/css" href="css/common.css">
        <script type="text/javascript" src="js/jquery.js"></script>
    </head>
    <body>
    <style type="text/css"> .animation-Box{ width: 600px; height: 400px; } .info-Box{ width: 600px; height: 400px; overflow: scroll; } .flow-chart{ text-align: center; } .flow-chart ul{ } .flow-chart ul li{ margin-top: 5px; border: 1px solid red; padding: 5px; margin: 5px; } .flow-chart ul li .reg{ background-color: #DB3434; color: #fff; padding: 5px 80px; font-size: 18px; } .flow-chart ul li .res{ background-color: #146E1F; color: #fff; padding: 2px 80px; font-size: 18px; height: 18px; line-height: 18px; } .content{ display: inline-block; vertical-align: middle; } .branch{ display: inline-block; vertical-align: middle; } #source{ width:800px; margin:20px auto 0; text-align:center; margin-bottom: 5px; } #source ul li{ margin-top: 5px; } #regexpInput,#textInput{ width: 500px; height: 30px; border: 1px solid gray; padding: 0 5px; } #beginBtn{ padding: 5px 15px; } text{ font-size: 20px; } </style>
        <div id="source">
            <ul >
                <li>正则表达式:<input type="text" id="regexpInput"/></li>
                <li><p style="color:red;">请填入正则表达式,支持格式:<br />1,没有斜线,如:<span style="font-size:20px;">\d|\s</span> ; <br />
                2,有斜线,如:<span style="font-size:20px;">/\d|\s/</span></p></li>
                <li><p style="color:red;">点击展示按钮,将会在下方生成正则流程图;同时在控制台中将会输出该正则的数据结构。</p></li>
                <li><p style="color:red;">请在高级浏览器中运行。</p></li>
                <li style="display:none;">需要匹配的字符串:<input type="text" id="textInput"/></li>
                <li><input type="button" id="beginBtn" value="展示流程图" /></li>
            </ul>
        </div>
        <style type="text/css"> path{ stroke:#000000; fill:none; stroke-width: 2px } rect{ fill:#bada55; } text{ fill:#000; } tspan{ } </style>
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="100%" width="100%" id="flowChart">
            <g></g>
        </svg>
        <div style="height:20px;position:fixed;top:0;left:0;text-algin:center;font-size:20px;font-weight:bold;background-color:white;" id="regFixed"></div>
    </body>
    <script type="text/javascript" src="js/require.js"></script>
    <script src="js/d3.v3.min.js" charset="utf-8"></script>
    <script src="js/dagre-d3.js"></script>
    <script type="text/javascript" src="js/main.js"></script>

    <script type="text/javascript"> require.config({ baseUrl: "js/" }); var regexpInputDom=document.getElementById('regexpInput'); var textInputDom=document.getElementById('textInput'); var beginBtnDom=document.getElementById('beginBtn'); beginBtnDom.onclick=function(){ require(['main'],function(main){ main.init(textInputDom.value,regexpInputDom.value); }); } $(window).scroll(function(){ if($(this).scrollTop()>40&&$('#regexpInput').val()!==''){ $('#regFixed').html($('#regexpInput').val()).show(); }else{ $('#regFixed').hide(); } }); </script>
</html>

common.css

body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{padding:0;margin:0}

address,caption,cite,code,dfn,em,var{font-style:normal;font-weight:normal}
pre,kbd,samp,tt{font-family:monospace;line-height:100%}
q:before,q:after{content:''}
abbr,acronym{border:0;font-variant:normal}
sup{vertical-align:text-top}
sub{vertical-align:text-bottom}

ul,li{list-style:none}
em,.em{font-style:italic}
strong,.strong{font-weight:bold}
img{border:0;vertical-align:top;-ms-interpolation-mode:bicubic}

/*==table==*/
table{border-collapse:collapse;border-spacing:0}
caption,th{text-align:left}

/*==Form==*/
fieldset{border:none}
legend{display:none}
textarea{resize:none}
button{overflow:visible}
label,button{cursor:pointer;_cursor:hand}
input,select,textarea{font:normal normal 14px "Verdana";color:#333;outline:none;/*去除Opera浏览器这些标签的默认样式*/}
textarea,input[type|="text"],input[type|="password"]{-webkit-appearance:none/*去除webkit浏览器这些标签的默认样式*/}
abbr[title],acronym[title]{border-bottom:1px dotted;cursor:help}
input[type="hidden"]{display:none!important}

/*==h1~h6==*/
h1,.h1{font-size:18px;font-weight:bold}
h2,.h2{font-size:16px;font-weight:bold}
h3,.h3{font-size:14px;font-weight:bold}
h4,.h4{font-size:14px;font-weight:normal}
h5,.h5{font-size:12px;font-weight:normal}
h6,.h6{font-size:12px;font-weight:normal}

/* 字体大小*/
.f12px{font-size:12px}
.f14px{font-size:14px}

/* 浮动*/
.fl{float:left}
.fr{float:right}

/*==通用链接==*/
a{color:#333;text-decoration:none;outline:none}
a:hover{text-decoration:underline;outline:none}
.blod a,.blod{font-weight:bold}

/* 其它属性*/
.center{text-align:center}
.mid{vertical-align:middle}
.hide{display:none}
.submit{cursor:pointer;border:0}

/*==collr==*/
.collr,.collr .colr{overflow:hidden;zoom:1}
.collr .coll{float:left;_margin-right:-3px}
.collr .coll img{vertical-align:top}

.p-collr{position:relative;zoom:1}
.p-collr .coll{position:absolute;left:0;top:0}
.p-collr .colr{zoom:1}

/*==clear==*/
.clear{clear:both;font-size:0px;width:0px;height:0;visibility:hidden;line-height:0}
.clearfix{*zoom:1}
.clearfix:after{content:"";display:block;height:0;clear:both;visibility:hidden}

body{background-color:#FFF;font:12px/22px Arial,Tahoma,Verdana,"\5B8B\4F53";color:#333}

main.js

define('main',['draw','Meta','NFA'],function(draw,Meta,NFA) {
    function init(inputStr,regexpStr) {
        if (regexpStr === '') {
            return;
        } else if (/^\//.test(regexpStr) && /(?:\/|\/i|\/g|\/m)$/.test(regexpStr)) {
            regexpStr = regexpStr.replace(/^\//,'').replace(/(\/|\/i|\/g|\/m)$/,'');
        }
        try {
            var reg = new RegExp(regexpStr);
        } catch (e) {
            alert(e);
        }
        var Metas = [];
        Meta(regexpStr,Metas,1);
        console.log('该正则表达式的生成数据结构如下:');
        console.log(Metas);
        var obj = document.getElementById('flowChart');
        draw.drawModel(Metas,obj);
        //NFA(inputStr,showMatch);
    }
    return {
        init: init
    }
});

draw.js

define('draw',['description'],function(des) {

    /*var getBreadth=function(arr){ var breadth=arr.length; var tempBreadth=0; for(var i=0,len=arr.length;i<len;i++){ tempBreadth=0; } };*/
    var obj = {
        drawModel: function(arr) {
            var g = new dagreD3.graphlib.Graph().setGraph({});
            g.setGraph({
                nodesep: 70,ranksep: 50,rankdir: "LR",marginx: 20,marginy: 20
            });
            var preNodes = [];
            var depth = [];
            var topIndex = 0;
            // node命名规则 'node'+顶级index+深度+分支号+名称+随机
            function drawBranch(branchArr,curPreNodes,type,operator) {
                //type = type ? type : '分支';
                depth.push(1);
                var curNodeName = '';
                var bPreNodes = [];
                var len = depth.length;


                if (type) {
                    preNodes = curPreNodes;
                    curNodeName = 'node' + topIndex + depth.length + 't' + 's' + Math.random();
                    g.setNode(curNodeName,{
                        label: '进入' + type
                    });
                    if (type === '捕获分组') {
                        g.node(curNodeName).style = "fill:#3B639F";
                    } else if (type === '非捕获分组') {
                        g.node(curNodeName).style = "fill:#f5f8fc";
                    } else if (type === '肯定环视') {
                        g.node(curNodeName).style = "fill:#10c2ce";
                    } else if (type === '否定环视') {
                        g.node(curNodeName).style = "fill:#BBFFFF";
                    }
                    preNodes.forEach(function(nodeName) {
                        g.setEdge(nodeName,curNodeName,{
                            //label: curNodeName
                            label: ''
                        });
                    });
                    curPreNodes = [curNodeName];
                    preNodes = curPreNodes;
                }

                for (var i = 0,len = branchArr.length; i < len; i++) { //进入分支
                    if (len !== 1) {
                        preNodes = curPreNodes;
                        curNodeName = 'node' + topIndex + depth.length + i + 's' + Math.random();
                        g.setNode(curNodeName,{
                            label: '进入' + '分支'
                        });

                        g.node(curNodeName).style = "fill:#aa73d1";
                        preNodes.forEach(function(nodeName) {
                            g.setEdge(nodeName,{
                                //label: curNodeName
                                label: ''
                            });
                        });
                        preNodes = [curNodeName];
                    }


                    for (var j = 0,c = branchArr[i].length; j < c; j++) {
                        // 顶级Index
                        if (depth.length === 1) {
                            topIndex = '' + i + j;
                        }
                        if (branchArr[i][j].branch.length === 0) { //内容元素
                            curNodeName = 'node' + topIndex + depth.length + i + j + Math.random();
                            g.setNode(curNodeName,{
                                label: des(branchArr[i][j].atom,j) + ' 匹配' + des(branchArr[i][j].operator,j,true)
                            });
                            preNodes.forEach(function(nodeName) {
                                g.setEdge(nodeName,{
                                    //label: curNodeName
                                    label: ''
                                });
                            });
                            preNodes = [curNodeName];
                        } else { //递归
                            preNodes = drawBranch(branchArr[i][j].branch,preNodes,branchArr[i][j].type,branchArr[i][j].operator);
                        }
                    }

                    if (len !== 1) {
                        curNodeName = 'node' + topIndex + depth.length + i + 'e' + Math.random();
                        g.setNode(curNodeName,{
                            label: ('分支' + '结束') + (operator ? ' 匹配' + des(operator,undefined,true) : '')
                        });

                        g.node(curNodeName).style = "fill:#aa73d1";
                        preNodes.forEach(function(nodeName) {
                            g.setEdge(nodeName,{
                                //label: curNodeName
                                label: ''
                            });
                        });
                        preNodes = [curNodeName];
                    }

                    bPreNodes.push(preNodes);
                }

                if (type) {
                    curNodeName = 'node' + topIndex + depth.length + 't' + 'e' + Math.random();
                    g.setNode(curNodeName,{
                        label: (type + '结束') + (operator ? ' 匹配' + des(operator,true) : '')
                    });
                    if (type === '捕获分组') {
                        g.node(curNodeName).style = "fill:#3B639F";
                    } else if (type === '非捕获分组') {
                        g.node(curNodeName).style = "fill:#f5f8fc";
                    } else if (type === '肯定环视') {
                        g.node(curNodeName).style = "fill:#10c2ce";
                    } else if (type === '否定环视') {
                        g.node(curNodeName).style = "fill:#BBFFFF";
                    }
                    bPreNodes.forEach(function(nodeName) {
                        g.setEdge(nodeName,{
                            //label: curNodeName
                            label: ''
                        });
                    });
                    preNodes = [curNodeName];
                    bPreNodes = preNodes;
                }
                depth.pop();
                return bPreNodes;
            }
            g.setNode('start',{
                label: 'start',title:'ssss'
            });
            preNodes.push('start');
            g.node('start').style = "fill: #999";
            //preNodes = drawBranch(arr,preNodes);
            preNodes = drawBranch(arr,preNodes);
            g.setNode('end',{
                label: 'end'
            });
            g.node('end').style = "fill: #999";
            preNodes.forEach(function(nodeName) {
                g.setEdge(nodeName,'end',{
                    //label: 'end'
                    label: ''
                });
            });
            // Set some general styles
            g.nodes().forEach(function(v) {
                var node = g.node(v);
                node.rx = node.ry = 5;
            });

            var svg = d3.select("svg"),inner = svg.select("g");

            // Create the renderer
            var render = new dagreD3.render();
            // Run the renderer. This is what draws the final graph.
            render(inner,g);
            // Center the graph
            //var initialScale = 0.75;
            var zoom = d3.behavior.zoom().on("zoom",function() {
                inner.attr("transform","scale(" + d3.event.scale + ")");
            });
            svg.call(zoom);
            var initialScale = Math.max(0.6,$(window).width() / g.graph().width);
            zoom
                .scale(initialScale)
                .event(svg);
            //svg.attr('height',g.graph().height * initialScale + 40);
            svg.attr('width',g.graph().width * initialScale);
            d3.selectAll('g').data([1,2,3,4,5,6,7]).enter().append('text').text(function(d){return d;});
        }
    };
    return obj;
});

Meta.js

define('Meta',function() {
    var operatorsReg = /^(?:\+\?|\*\?|\?\?|\+|\*|\?|\{\d+,\d*\}\??|\{\d+,?\}\??)/;

    function findOperator(str) {
        var oResult = operatorsReg.exec(str);
        if (oResult === null) {
            return {
                operator: '',length: 0
            }
        } else {
            return {
                operator: oResult[0],length: oResult[0].length
            }
        }
    }

    function readGroup(str) {
        var r = /[(|)]|\(\?\:/g,res,leftGroup = [],rightGroup = [],orGroup = [];
        var tempStr = str.replace(/\\./g,'&&');
        while (res = r.exec(str)) {
            if (res[0] === '(' || res[0] === '(?:') {
                leftGroup.push(r.lastIndex - 1);
            } else if (res[0] === '|') {
                orGroup.push(r.lastIndex - 1);
            } else if (res[0] === ')') {
                rightGroup.push(r.lastIndex - 1);
            }
        }

        var paraArr = [],tempParaCL = 0,tempParaCR = 0,paraL = 0,paraR = 0;
        for (var k = 0,b = 0,c = tempStr.length; k < c; k++) {
            tempParaCL = 0,paraR = 0;
            if (tempStr.charAt(k) === '(') {
                paraL = k;
                for (b = k + 1; b < c; b++) {
                    if (tempStr.charAt(b) === ')') {
                        tempParaCR++;
                        if (tempParaCR > tempParaCL) {
                            paraR = b;
                            paraArr.push({
                                l: paraL,r: paraR
                            });
                            break;
                        }
                    } else if (tempStr.charAt(b) === '(') {
                        tempParaCL++;
                    }
                }

            }
        }

        var resArr = [];
        if (leftGroup.length === 0) {
            if (orGroup.length) {
                for (var j = 0,l = orGroup.length; j < l; j++) {
                    if (j === 0) {
                        resArr.push({
                            l: 0,r: orGroup[j] - 1,or: orGroup[j]
                        });
                    } else {
                        resArr.push({
                            l: orGroup[j - 1] + 1,or: orGroup[j]
                        });
                    }
                }
            } else {
                resArr = [];
            }
        } else {
            if (orGroup.length) {
                var tempCountL = 0,tempCountR = 0,realL = 0,realR = 0;
                for (var j = 0,l = orGroup.length; j < l; j++) {
                    tempCountL = 0,realR = 0;
                    for (var n = orGroup[j]; n > 0; n--) {
                        if (tempStr[n] === ')') {
                            tempCountR++;
                        } else if (tempStr[n] === '(') {
                            tempCountL++;
                            if (tempCountL > tempCountR) {
                                realL = n;
                                break;
                            }
                        }
                    }
                    tempCountL = 0,tempCountR = 0;
                    for (n = orGroup[j]; n < tempStr.length; n++) {
                        if (tempStr[n] === '(') {
                            tempCountL++;
                        } else if (tempStr[n] === ')') {
                            tempCountR++;
                            if (tempCountR > tempCountL) {
                                realR = n;
                                break;
                            }
                        }
                    }
                    resArr.push({
                        l: realL,r: realR,or: orGroup[j]
                    });
                }
            } else {
                resArr = [];
            }
        }
        return {
            leftGroup: leftGroup,rightGroup: rightGroup,orGroup: orGroup,resArr: resArr,paraArr: paraArr
        }
    }

    function getRightPara(leftPara,paraArr) {
        for (var i = 0,len = paraArr.length; i < len; i++) {
            if (paraArr[i].l === leftPara) {
                return paraArr[i].r;
            }
        }
    }

    var groupIndex = 1;

    function parseMeta(str,arr,isInit) {
        if (isInit) {
            groupIndex = 1;
        }
        var groupObj = readGroup(str);
        var atIndex = 0,atChar = '',tempAtom = '',isUnicode = false,isHex = false,paraRight = 0,finaIndex = 0;
        for (var len = str.length; atIndex < len; atIndex++) {
            isUnicode = false;
            isHex = false;
            atChar = str.charAt(atIndex);
            //finaIndex=arr.length;
            if (arr[finaIndex] === undefined) {
                arr[finaIndex] = [];
            }
            arr[finaIndex][arr[finaIndex].length] = {};
            if (atChar === '\\') {
                subStr = str.substring(atIndex + 1);
                if (/^u[0-9a-fA-F]{4}/.test(subStr)) { // unicode转义
                    tempAtom = '\\\\' + /^u[0-9a-fA-F]{4}/.exec(subStr)[0];
                    isUnicode = true;
                    atIndex += 5;
                } else {
                    isUnicode = false;
                }
                if (/^x[0-9a-fA-F]{2}/.test(subStr)) { // 16进制转义
                    tempAtom = '\\\\' + /^x[0-9a-fA-F]{2}/.exec(subStr);
                    atIndex += 3;
                    isHex = true;
                } else {
                    isHex = false;
                }
                if (!isUnicode && !isHex) {
                    tempFun = makeMeta(atChar);
                    atIndex++;
                    tempAtom = tempFun(str.charAt(atIndex));
                }

                arr[finaIndex][arr[finaIndex].length - 1].index = atIndex;

                arr[finaIndex][arr[finaIndex].length - 1].atom = tempAtom;

                operatorObj = findOperator(str.substring(atIndex + 1));
                arr[finaIndex][arr[finaIndex].length - 1].operator = operatorObj.operator;
                atIndex += operatorObj.length;

                arr[finaIndex][arr[finaIndex].length - 1].branch = [];

                arr[finaIndex][arr[finaIndex].length - 1].length = 0;
            } else if (atChar === '[') {
                arr[finaIndex][arr[finaIndex].length - 1].index = atIndex;

                subStr = str.substring(atIndex);
                tempFun = makeMeta('');
                tempAtom = tempFun((/\[.*?(?=([^\\])(\]))/.exec(subStr)[0]) + (/\[.*?(?=([^\\])(\]))/.exec(subStr)[1]) + (/\[.*?(?=([^\\])(\]))/.exec(subStr)[2]));
                atIndex += tempAtom.length;
                arr[finaIndex][arr[finaIndex].length - 1].atom = tempAtom;

                operatorObj = findOperator(str.substring(atIndex));
                arr[finaIndex][arr[finaIndex].length - 1].operator = operatorObj.operator;
                atIndex += operatorObj.length - 1;

                arr[finaIndex][arr[finaIndex].length - 1].branch = [];

                arr[finaIndex][arr[finaIndex].length - 1].length = 0;
            } else if (atChar === '|') {
                arr[finaIndex].pop();
                finaIndex++;
                if (atIndex === 0) {
                    arr[finaIndex - 1] = [];
                    arr[finaIndex - 1][0] = {};
                    arr[finaIndex - 1][0].index = atIndex;

                    tempAtom = '';
                    arr[finaIndex - 1][0].atom = tempAtom;

                    arr[finaIndex - 1][0].operator = '';

                    arr[finaIndex - 1][0].branch = [];

                    arr[finaIndex - 1][0].length = 0;
                }
                if (atIndex === str.length - 1 || str[atIndex + 1] === '|') {

                    arr[finaIndex] = [];
                    arr[finaIndex][0] = {};
                    arr[finaIndex][0].index = atIndex;

                    tempAtom = '';
                    arr[finaIndex][0].atom = tempAtom;

                    arr[finaIndex][0].operator = '';

                    arr[finaIndex][0].branch = [];

                    arr[finaIndex][0].length = 0;
                }
            } else if (atChar === '(') {
                paraRight = getRightPara(atIndex,groupObj.paraArr);

                arr[finaIndex][arr[finaIndex].length - 1].index = atIndex;

                subStr = str.substring(atIndex + 1,paraRight);
                if (/^\?:/.test(subStr)) {
                    atIndex += 2;
                    subStr = /^\?:(.*)$/.exec(subStr)[1];
                    arr[finaIndex][arr[finaIndex].length - 1].type = '非捕获分组';
                } else if (/^\?=/.test(subStr)) {
                    atIndex += 2;
                    subStr = /^\?=(.*)$/.exec(subStr)[1];
                    arr[finaIndex][arr[finaIndex].length - 1].type = '肯定环视';
                } else if (/^\?!/.test(subStr)) {
                    atIndex += 2;
                    subStr = /^\?!(.*)$/.exec(subStr)[1];
                    arr[finaIndex][arr[finaIndex].length - 1].type = '否定环视';
                } else {
                    arr[finaIndex][arr[finaIndex].length - 1].type = '捕获分组' + groupIndex++;
                }
                atIndex += subStr.length + 1;
                arr[finaIndex][arr[finaIndex].length - 1].atom = subStr;

                operatorObj = findOperator(str.substring(atIndex + 1));
                arr[finaIndex][arr[finaIndex].length - 1].operator = operatorObj.operator;
                atIndex += operatorObj.length;

                arr[finaIndex][arr[finaIndex].length - 1].branch = [];
                parseMeta(subStr,arr[finaIndex][arr[finaIndex].length - 1].branch);
                arr[finaIndex][arr[finaIndex].length - 1].length = 0;
            } else {
                arr[finaIndex][arr[finaIndex].length - 1].index = atIndex;

                tempAtom = str.charAt(atIndex);
                arr[finaIndex][arr[finaIndex].length - 1].atom = tempAtom;

                operatorObj = findOperator(str.substring(atIndex + 1));
                arr[finaIndex][arr[finaIndex].length - 1].operator = operatorObj.operator;
                atIndex += operatorObj.length;

                arr[finaIndex][arr[finaIndex].length - 1].branch = [];

                arr[finaIndex][arr[finaIndex].length - 1].length = 0;
            }
        }
    }

    function makeMeta(firstChar) {
        var Meta = firstChar;
        return function(atChar) {
            Meta += atChar;
            return Meta;
        }
    }
    return parseMeta;
});

运行结果如图:



猜你在找的正则表达式相关文章