antlr4 正则表达式生成器2解决中文生成问题

1、中文生成问题

中文生成主要是无法解析unicode 编码的字符,当前的词法分析会进行分解 如 [\u4E00] 会拆分

2、解决思路

在解析为 xmlChar的时候,优先加入 中文编码的处理

regexLexer.g4 词法文件,添加中文编码处理

css 复制代码
Chinese_Unicode     : '\u' [a-z0-9A-Z]+;

语法文件 regexParser.g4

  • 处理单字符场景 [\u2E80]
arduino 复制代码
charGroup
    : posCharGroup? DASH DASH charClassExpr
    | posCharGroup DASH charClassExpr
    | posCharGroup DASH?
    | DASH
    | Chinese_Unicode // 添加了中文编码处理
    ;
  • 处理区间范围场景 [\u2E80-\u2E88]
arduino 复制代码
charOrEsc
    : Chinese_Unicode // 前置添加中文编码处理
    | XmlChar
    | SingleCharEsc
    ;

3、代码修改

1、修改完词法和语法的g4文件

regexLexer.g4

less 复制代码
/*
 * [The "BSD license"]
 *  Copyright (c) 2019 PANTHEON.tech
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Lexer grammar for https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs.
 *
 * This grammar is modified in following ways:
 * - we use lexer modes to disambiguate between Char, XmlChar and QuantExact
 * - we use separate lexer tokens to disambiguate positive and negative character groups
 * - XmlCharIncDash is removed in favor of DASH token, which is handled in parser
 */

// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine
// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true

lexer grammar regexLexer;

LPAREN      : '(';
RPAREN      : ')';
PIPE        : '|';
PLUS        : '+';
QUESTION    : '?';
STAR        : '*';
WildcardEsc : '.';
Char        : ~('.' | '\' | '?' | '*' | '+' | '(' | ')' | '|' | '[' | ']' | '{' | '}');

// Quantifier's quantity rule support
StartQuantity: '{' -> pushMode(QUANTITY);

// Single Character Escape
SingleCharEsc: SINGLE_ESC;

// Multi-Character Escape
MultiCharEsc: MULTI_ESC;

// Category Escape
CatEsc   : CAT_ESC   -> pushMode(CATEGORY);
ComplEsc : COMPL_ESC -> pushMode(CATEGORY);

// Positive/Negative Character Group
NegCharGroup : '[^' -> pushMode(CHARGROUP);
PosCharGroup : '['  -> pushMode(CHARGROUP);

mode QUANTITY;
EndQuantity : '}' -> popMode;
QuantExact  : [0-9]+;
COMMA       : ',';

mode CATEGORY;
EndCategory: '}' -> popMode;

// Categories
IsCategory  : Letters | Marks | Numbers | Punctuation | Separators | Symbols | Others;
Letters     : 'L' [ultmo]?;
Marks       : 'M' [nce]?;
Numbers     : 'N' [dlo]?;
Punctuation : 'P' [cdseifo]?;
Separators  : 'Z' [slp]?;
Symbols     : 'S' [mcko]?;
Others      : 'C' [cfon]?;

// Block Escape
IsBlock: 'Is' ([a-z0-9A-Z] | '-')+;

mode CHARGROUP;
NestedSingleCharEsc : SINGLE_ESC;
NestedMultiCharEsc  : MULTI_ESC;
NestedCatEsc        : CAT_ESC   -> pushMode(CATEGORY);
NestedComplEsc      : COMPL_ESC -> pushMode(CATEGORY);
NestedNegCharGroup  : '[^'      -> pushMode(CHARGROUP);
NestedPosCharGroup  : '['       -> pushMode(CHARGROUP);
EndCharGroup        : ']'       -> popMode;
DASH                : '-';
Chinese_Unicode     : '\u' [a-z0-9A-Z]+;
XmlChar             : ~('-' | '[' | ']')  ;

fragment CAT_ESC    : '\p{';
fragment COMPL_ESC  : '\P{';
fragment MULTI_ESC  : '\' [sSiIcCdDwW];
fragment SINGLE_ESC : '\' [nrt\|.?*+(){}\u002D\u005B\u005D\u005E];

regexParser.g4

less 复制代码
/*
 * [The "BSD license"]
 *  Copyright (c) 2019 PANTHEON.tech
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Parser grammar for https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs.
 *
 * This grammar is modified in following ways:
 * - charGroup definition inlines the charClassSub case
 *   This allows us to simplify processing, eliminating one level of nesting. It
 *   also makes this rule consistent with XSD 1.1 definition.
 */

// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging

parser grammar regexParser;

options {
    tokenVocab = regexLexer;
}

// Parser root context, ensures all input is matched
root
    : regExp EOF
    ;

// Regular Expression
regExp
    : branch (PIPE branch)*
    ;

// Branch
branch
    : piece*
    ;

// Piece
piece
    : atom quantifier?
    ;

// Quantifier
quantifier
    : QUESTION
    | STAR
    | PLUS
    | StartQuantity quantity EndQuantity
    ;

quantity
    : quantRange
    | quantMin
    | QuantExact
    ;

quantRange
    : QuantExact COMMA QuantExact
    ;

quantMin
    : QuantExact COMMA
    ;

// Atom
atom
    : Char
    | charClass
    | (LPAREN regExp RPAREN)
    ;

// Character Class
charClass
    : charClassEsc
    | charClassExpr
    | WildcardEsc
    ;

// Character Class Expression
charClassExpr
    : (NegCharGroup | NestedNegCharGroup | PosCharGroup | NestedPosCharGroup) charGroup EndCharGroup
    ;

// Character Group
// In order to disambiguate the use of DASH's roles in Character Class Subtraction and in posCharGroup
// tail, we explicitly handle it here. ANTLR will consider the subrules in order and they completely
// disambiguate use [a--[f]], [a-[f]], [a-], [a]. We have borrowed some of the clarification from
// https://www.w3.org/TR/2012/REC-xmlschema11-2-20120405/ to make this work
charGroup
    : posCharGroup? DASH DASH charClassExpr
    | posCharGroup DASH charClassExpr
    | posCharGroup DASH?
    | DASH
    | Chinese_Unicode // 添加了中文编码处理
    ;

// Positive Character Group
posCharGroup
    : DASH? (charRange | charClassEsc)+
    ;

// Character Range, sans the DASH possibility
charRange
    : seRange
    | XmlChar
    ;

seRange
    : charOrEsc DASH charOrEsc
    ;

charOrEsc
    : Chinese_Unicode // 前置添加中文编码处理
    | XmlChar
    | SingleCharEsc
    ;

// Character Class Escape
charClassEsc
    : SingleCharEsc
    | NestedSingleCharEsc
    | MultiCharEsc
    | NestedMultiCharEsc
    | catEsc
    | complEsc
    ;

// Category Escape
catEsc
    : (CatEsc | NestedCatEsc) charProp EndCategory
    ;

complEsc
    : (ComplEsc | NestedComplEsc) charProp EndCategory
    ;

charProp
    : IsCategory
    | IsBlock
    ;

2、重新生成代码

3、调整遍历器

  • charGroup 调整
java 复制代码
//    charGroup
//    : posCharGroup? DASH DASH charClassExpr
//    | posCharGroup DASH charClassExpr
//    | posCharGroup DASH?
//    | DASH
//    | Chinese_Unicode // 添加了中文编码处理
//    ;
    @Override
    public String visitCharGroup(regexParser.CharGroupContext ctx) {

        List<String> datas = new ArrayList<>();
        // 对中文字符进行处理
        if (ctx.Chinese_Unicode() != null) {
            // 获取unicode 编码
            String text = ctx.Chinese_Unicode().getText();
            // 生成中文,使用了hutool库
            String chinese = UnicodeUtil.toString(text);
            // 添加到选择列表中
            datas.add(chinese);
            // 处理完,就返回
            return datas.get(R.nextInt(datas.size()));
        }

        // 获取一个列表
        datas.add(visitPosCharGroup(ctx.posCharGroup()));

        // 获取任意一个
        return datas.get(R.nextInt(datas.size()));
    }
  • visitSeRange 调整
java 复制代码
//    charOrEsc
//    : Chinese_Unicode
//    | XmlChar
//    | SingleCharEsc
//    ;
    @Override
    public String visitSeRange(regexParser.SeRangeContext ctx) {

        // [a-w] [0-9]
        String start = ctx.charOrEsc(0).getText();
        String end = ctx.charOrEsc(1).getText();

        // 判断为中文处理
        if (start.startsWith("\u")) {
            // 获取unicode,转为 16进制字符串
            String hexStartStr = start.replace("\u", "");
            String hexEndStr = end.replace("\u","");
            // 16进制转为10进制
            int hexStart = HexUtil.hexToInt(hexStartStr);
            int hexEnd = HexUtil.hexToInt(hexEndStr);
             // 使用hutool库生成字符串
            char chinese = (char)RandomUtil.randomInt(hexStart, hexEnd + 1);
            return new String(new char[]{chinese});
        }
        // 返回随机数
        return randomChar(start.charAt(0),end.charAt(0));
    }

4、测试

java 复制代码
public static void main(String[] args) {

    // 生成5个中文字符
    System.out.println(RegexUtil.gen("[\u2E80]{5}"));

    // 生成10个中文字符
    System.out.println(RegexUtil.gen("[\u2E80-\u2EFF\u2F00-\u2FDF\u31C0-\u31EF]{10}"));

}

输出如下:

⺀⺀⺀⺀⺀
⺶㇌⽗⺿⺙⺄⺡⽍⾧㇥

5、完整的访问器代码如下:

RegVistor2.java

java 复制代码
package com.regex;

import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import com.regex.g4.regexParser;
import com.regex.g4.regexParserBaseVisitor;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 遍历整个正则的语法分析树
 */
public class RegVistor2 extends regexParserBaseVisitor<String> {

    // 随机字符串
    private final static Random R = new Random();

    // 是否包含特殊字符
    private final static Boolean MAYBE_SPECIAL_CHAR = Boolean.TRUE;


    //    root
    //    : regExp EOF
    //            ;
    @Override
    public String visitRoot(regexParser.RootContext ctx) {
        // 直接访问子节点
        return visitRegExp(ctx.regExp());
    }


    //    regExp
//    : branch (PIPE branch)*
//    ;
    @Override
    public String visitRegExp(regexParser.RegExpContext ctx) {

        // 或者任意一个分支的结果即可
        int index = R.nextInt(ctx.branch().size());
        // 获取其中一个分支的结果
        return visitBranch(ctx.branch(index));
    }

    //    branch
//    : piece*
//    ;
    @Override
    public String visitBranch(regexParser.BranchContext ctx) {
        StringBuilder stringBuilder = new StringBuilder();
        // 遍历piece 结果,即可或者所有的结果
        for (regexParser.PieceContext pieceContext : ctx.piece()) {
            stringBuilder.append(visitPiece(pieceContext));
        }
        return stringBuilder.toString();
    }

    //    piece
//    : atom quantifier?
//    ;
    @Override
    public String visitPiece(regexParser.PieceContext ctx) {
        StringBuilder sb = new StringBuilder();
        // 获取字符
        regexParser.AtomContext atom = ctx.atom();
        // quantifier 次数
        regexParser.QuantifierContext quantifier = ctx.quantifier();
        if (quantifier != null) {
            String num = visitQuantifier(quantifier);
            Integer regCount = Integer.valueOf(num);
            for (Integer i = 0; i < regCount; i++) {
                String data = visitAtom(atom);
                sb.append(data);
            }
            return sb.toString();
        }
        // 只有字符就返回生成的字符
        return visitAtom(atom);
    }



    //    atom
//    : Char
//    | charClass
//    | (LPAREN regExp RPAREN)
//    ;
    @Override
    public String visitAtom(regexParser.AtomContext ctx) {
        // 字符直接匹配
        if (ctx.Char() != null) {
            return ctx.Char().getText();
        }
        // 其他访问子分支
        if (ctx.charClass() != null) {
            return visitCharClass(ctx.charClass());
        }

        if (ctx.regExp() != null) {
            return visitRegExp(ctx.regExp());
        }

        return "";
    }

    //    charClass
//    : charClassEsc
//    | charClassExpr
//    | WildcardEsc
//    ;
    @Override
    public String visitCharClass(regexParser.CharClassContext ctx) {
        // 都是优先处理终结符  匹配. 返回一个任意字符
        if (ctx.WildcardEsc() != null) {
            // 返回一个任意字符,
            int[][] range = {{0x4e00, 0x9fa5}, {0x30, 0x39}, {0x61, 0x7a}, {0x41, 0x5a}};
            return getRandomChar(range);
        }
        // 访问其他子节点
        if (ctx.charClassEsc() != null) {
            return visitCharClassEsc(ctx.charClassEsc());
        }

        if (ctx.charClassExpr() != null) {
            return visitCharClassExpr(ctx.charClassExpr());
        }
        return "";
    }

    // 生成随机字符串
    private String getRandomChar(int[][] range) {

        String specialCharStr = "!@#$%^&*()_+|\\/?'"',,<>,.·~`";
        // 包含特殊字符
        if (RegVistor2.MAYBE_SPECIAL_CHAR && R.nextBoolean()) {
            return String.valueOf(specialCharStr.charAt(R.nextInt(specialCharStr.length())));
        } else {
            // 随机选择一组
            int[] subRange = range[R.nextInt(range.length)];
            char charValue = (char) (subRange[0] + R.nextInt(subRange[1] - subRange[0] + 1));
            return String.valueOf(charValue);
        }
    }


    //    charClassEsc
//    : SingleCharEsc
//    | NestedSingleCharEsc
//    | MultiCharEsc
//    | NestedMultiCharEsc
//    | catEsc
//    | complEsc
//    ;
    @Override
    public String visitCharClassEsc(regexParser.CharClassEscContext ctx) {

        // 单字符
        if (ctx.SingleCharEsc() != null) {
            return ctx.SingleCharEsc().getText();
        }
        // 反逻辑单字符
        if (ctx.NestedSingleCharEsc() != null) {
            return ctx.NestedSingleCharEsc().getText();
        }
        // /d /w 等处理
        if (ctx.MultiCharEsc() != null) {
            return getMultiCharEscStr(ctx.MultiCharEsc().getText());
        }
        // /D 反逻辑处理
        if (ctx.NestedMultiCharEsc() != null) {
            return getMultiCharEscStr(ctx.NestedMultiCharEsc().getText());
        }
        // 访问子节点
        if (ctx.catEsc() != null || ctx.complEsc() != null) {
            throw new RuntimeException("不支持catEsc,和 complEsc");
        }
        return "";
    }

    /**
     * 根据字符,来或者返回的字符
     * @param text
     * @return
     */
    private String getMultiCharEscStr(String text) {

        List<String> rangeList = new ArrayList();
        switch (text) {
            // 空白字符
            case "\\s":
                rangeList.add(randomChar(' ', ' '));
                rangeList.add(randomChar('\t', '\t'));
                rangeList.add(randomChar('\r', '\r'));
                rangeList.add(randomChar('\n', '\n'));
                break;
            case "\\S":

                rangeList.add(randomChar(0x4e00, 0x9fa5));
                rangeList.add(randomChar(0x30, 0x39));
                rangeList.add(randomChar(0x61, 0x7a));
                rangeList.add(randomChar(0x41, 0x5a));

                break;

            case "\\i":
            case "\\c":
            case "\\C":
            case "\\I":
                throw new  RuntimeException("notSupportExp_i_I_c_C");
            case "\\d":

                rangeList.add(randomChar(0x30, 0x39));
                break;


            case "\\D":
                // \D:表示非数字
                rangeList.add(randomChar(0x4e00, 0x8fa5));
                rangeList.add(randomChar(0x61, 0x7a));
                rangeList.add(randomChar(0x41, 0x5a));
                break;


            case "\\w":
                // \w 表示匹配大小写英文字母、数字以及下划线,等价于'[a-za-z0-9_]'。
                rangeList.add(randomChar(0x61, 0x7a));
                rangeList.add(randomChar(0x41, 0x5a));
                rangeList.add(randomChar(0x30, 0x39));

                break;
            case "\\W":
                // \W :匹配任何非单词字符,等价于 [^A-Z a-z 0-9_]
                rangeList.add(randomChar(0x4e00, 0x9fa5));
                break;

        }

        return rangeList.get(R.nextInt(rangeList.size()));
    }


    // Character Class Expression
////    charClassExpr
////    : (NegCharGroup | NestedNegCharGroup | PosCharGroup | NestedPosCharGroup) charGroup EndCharGroup
//            ;
    @Override
    public String visitCharClassExpr(regexParser.CharClassExprContext ctx) {

        // 同时有 [^ 或者 [ 暂不支持
        if (ctx.NestedNegCharGroup() != null || ctx.NestedPosCharGroup() != null) {
            throw new RuntimeException("notSupportNestedCharGroup()");
        }
        return visitCharGroup(ctx.charGroup());
    }


//    charGroup
//    : posCharGroup? DASH DASH charClassExpr
//    | posCharGroup DASH charClassExpr
//    | posCharGroup DASH?
//    | DASH
//    | Chinese_Unicode // 添加了中文编码处理
//    ;
    @Override
    public String visitCharGroup(regexParser.CharGroupContext ctx) {

        List<String> datas = new ArrayList<>();
        // 对中文字符进行处理
        if (ctx.Chinese_Unicode() != null) {
            // 获取unicode 编码
            String text = ctx.Chinese_Unicode().getText();
            // 生成中文,使用了hutool库
            String chinese = UnicodeUtil.toString(text);
            // 添加到选择列表中
            datas.add(chinese);
            // 处理完,就返回
            return datas.get(R.nextInt(datas.size()));
        }

        // 获取一个列表
        datas.add(visitPosCharGroup(ctx.posCharGroup()));

        // 获取任意一个
        return datas.get(R.nextInt(datas.size()));
    }


    // Positive Character Group
//    posCharGroup
//    : DASH? (charRange | charClassEsc)+
//    ;
    @Override
    public String visitPosCharGroup(regexParser.PosCharGroupContext ctx) {
        List<String> datas = new ArrayList<>();
        if(ctx.DASH() != null) {
            datas.add("-");
        }
        // 添加到可选项中
        for (regexParser.CharClassEscContext charClassEscContext : ctx.charClassEsc()) {
            datas.add(visitCharClassEsc(charClassEscContext));
        }
        //  添加到可选项中
        for (regexParser.CharRangeContext charRangeContext : ctx.charRange()) {
            datas.add(visitCharRange(charRangeContext));
        }
        // 获取任意一个
        return datas.get(R.nextInt(datas.size()));
    }



//    charRange
//    : seRange
//    | XmlChar
//    ;

    @Override
    public String visitCharRange(regexParser.CharRangeContext ctx) {

        if (ctx.XmlChar() != null) {
            return ctx.XmlChar().getText();
        }
        // 接着访问子节点
        return super.visitCharRange(ctx);
    }


//    charOrEsc
//    : Chinese_Unicode
//    | XmlChar
//    | SingleCharEsc
//    ;
    @Override
    public String visitSeRange(regexParser.SeRangeContext ctx) {

        // [a-w] [0-9]
        String start = ctx.charOrEsc(0).getText();
        String end = ctx.charOrEsc(1).getText();

        // 判断为中文处理
        if (start.startsWith("\\u")) {
            // 获取unicode,转为 16进制字符串
            String hexStartStr = start.replace("\\u", "");
            String hexEndStr = end.replace("\\u","");
            // 16进制转为10进制
            int hexStart = HexUtil.hexToInt(hexStartStr);
            int hexEnd = HexUtil.hexToInt(hexEndStr);
             // 使用hutool库生成字符串
            char chinese = (char)RandomUtil.randomInt(hexStart, hexEnd + 1);
            return new String(new char[]{chinese});
        }
        // 返回随机数
        return randomChar(start.charAt(0),end.charAt(0));
    }


    //    quantifier
//    : QUESTION
//    | STAR
//    | PLUS
//    | StartQuantity quantity EndQuantity
//    ;
    @Override
    public String visitQuantifier(regexParser.QuantifierContext ctx) {

        // 匹配?,就返回随机值,0或者1
        if (ctx.QUESTION() != null) {
            return String.valueOf(R.nextInt(2));
        }
        // 匹配 * 号,返回 0-15 之间的数字
        if (ctx.STAR() != null) {
            return String.valueOf(R.nextInt(15));
        }
        // 匹配+  1到21 之间的整数,
        if (ctx.PLUS() != null) {
            return String.valueOf(R.nextInt(20) + 1);
        }
        // 有进行处理
        if (ctx.quantity() != null) {
            return visitQuantity(ctx.quantity());
        }
        return "0";
    }

    //    quantity
//    : quantRange
//    | quantMin
//    | QuantExact
//    ;
    @Override
    public String visitQuantity(regexParser.QuantityContext ctx) {
        // 这种情况要进行特殊处理下
        if (ctx.QuantExact() != null) {
            return ctx.QuantExact().getText();
        }

        if (ctx.quantMin() != null) {
            return visitQuantMin(ctx.quantMin());
        }

        if (ctx.quantRange() != null) {
            return visitQuantRange(ctx.quantRange());
        }
        return "0";
    }

//    quantRange
//    : QuantExact COMMA QuantExact
//    ;  {4,9} 等

    @Override
    public String visitQuantRange(regexParser.QuantRangeContext ctx) {
        TerminalNode terminalNodeMin = ctx.QuantExact(0);
        TerminalNode terminalNodeMax = ctx.QuantExact(1);

        int min = Integer.parseInt(terminalNodeMin.getText());

        int max = Integer.parseInt(terminalNodeMax.getText());

        if (min > max) {
            throw new RuntimeException("范围错误");
        }
        // 从可选范围中,选中一个
        return String.valueOf(min + R.nextInt(max - min + 1));
    }


    //    quantMin
//    : QuantExact COMMA
//            ; {8,}
    @Override
    public String visitQuantMin(regexParser.QuantMinContext ctx) {

        if (ctx.QuantExact() != null) {
            TerminalNode terminalNode = ctx.QuantExact();
            String text = terminalNode.getText();
            int min = Integer.parseInt(text);
            // 最小数 min - min+10
            return String.valueOf(R.nextInt(10) + min);
        }
        return "0";
    }

    /**
     * 生成随机字符串
     * @param start
     * @param end
     * @return
     */
    public String randomChar(int start,int end) {
        Random random = new Random();
        return String.valueOf((char) (start + random.nextInt(end - start + 1)));
    }

}
相关推荐
wn53141 分钟前
【Go - 类型断言】
服务器·开发语言·后端·golang
希冀1231 小时前
【操作系统】1.2操作系统的发展与分类
后端
GoppViper2 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文3 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people3 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
罗政8 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
拾光师10 小时前
spring获取当前request
java·后端·spring
Java小白笔记11 小时前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
JOJO___13 小时前
Spring IoC 配置类 总结
java·后端·spring·java-ee
白总Server14 小时前
MySQL在大数据场景应用
大数据·开发语言·数据库·后端·mysql·golang·php