【Java Compile】建表语句Java解析器

【代码下载】

https://files.cnblogs.com/files/heyang78/TableParser220825.rar?t=1661420885

【目标】

解析Oracle 建表语句文本,从中取出表名、表注释、字段名、字段注释、字段类型、是否主键等信息

【待解析文本示例】

复制代码
create table emp01(
    id number(12),
    name nvarchar2(20),
    age number(3),
    salary number(10,2),
    dept_id number(12),
    primary key(id)
);

comment on table emp01 is '雇员表';
comment on column emp01.id is 'ID';
comment on column emp01.name is '雇员名称';
comment on column emp01.age is '年龄';
comment on column emp01.salary is '薪水';
comment on column emp01.dept_id is '所在部门ID';

create table dept01(
    id number(12),
    name nvarchar2(20),
    primary key(id)
);

comment on table dept01 is '部门表';
comment on column dept01.id is 'ID';
comment on column dept01.name is '部门名称';
复制代码

【解析前的观察】

待解析文本是以句为单位,共有注释、表定义、表结束、字段定义、注释等五种,五种句式之间没有明显的依赖关系;

句式之内不存在嵌套,要得到表和字段信息只要找到特定token即可;

该任务类似QBasic的解析。

【代码】

入口类:

复制代码
package com.hy;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * 程序入口
 * 在main中读取文件、分词、分析
 * @author hy
 * @since 2022年8月24日
 */
public class Starter {
    
    /**
     * 入口函数
     * @param args
     */
    public static void main(String[] args)  throws Exception{
        // 从文本文件获得要解析的文本
        final String rawTxt=readTextFromFile("C:\\hy\\sql\\createTb.sql");
        System.out.println("Raw text="+rawTxt);
        
        // 启动分词器
        Lexer lex=new Lexer(rawTxt);
        lex.printTokens();
        
        // 启动分析器
        Parser parser=new Parser(lex.getTokens());
        parser.run();
        
        String tableDesc=parser.getTablesDesc();
        write2File("c:\\hy\\1.txt",tableDesc);
    }
    
    /**
     * 从文本文件中读取文件内容
     * @param filePath 文本文件路径文件名
     * @return 文件内容
     * @throws Exception
     */
    private static String readTextFromFile(String filePath) throws Exception{
        File file=new File(filePath);
        if(!file.exists()) {
            throw new Exception(String.format("File:%s does not exist.", filePath));
        }
        
        StringBuilder sb=new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));  
        String line = null;  
        while( ( line = br.readLine() ) != null ) {
            sb.append(line+"\r");// 在行末尾主动添加回车符
        }
        br.close();  
        return sb.toString();
    }
    
    // 将内容存入文本文件
    private static void write2File(String path,String content) throws Exception{
        FileOutputStream writerStream = new FileOutputStream(path);
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(writerStream, "UTF-8"));
        writer.write(content);
        writer.close();
    }
}
复制代码

 

标记类:

复制代码
package com.hy;

/**
 * 标记类
 * 
 * @author hy
 * @since 2022年8月24日
 */
public class Token {
    // 符号标记
    public static final int TYPE_SYMBOL_OPEN_PARENTHESIS=101;      // (
    public static final int TYPE_SYMBOL_CLOSE_PARENTHESIS=102;    // )
    public static final int TYPE_SYMBOL_COMMA=103;                // ,
    public static final int TYPE_SYMBOL_SEMICOLON=104;            // ;
    public static final int TYPE_SYMBOL_SINGLE_QUOTA=105;        // '
    public static final int TYPE_SYMBOL_DOUBLE_MIDDLE_LINE=106;    // --
    public static final int TYPE_SYMBOL_EQUAL=107;                // =
    public static final int TYPE_SYMBOL_GREATER_THAN=108;        // >
    public static final int TYPE_SYMBOL_GREATER_EQUAL_THAN=109;    // >=
    public static final int TYPE_SYMBOL_LESS_THAN=110;            // <
    public static final int TYPE_SYMBOL_LESS_EQUAL_THAN=111;    // <=
    public static final int TYPE_SYMBOL_DOT=112;                // .
    public static final int TYPE_SYMBOL_END_OF_LINE=113;        // \r
    
    // 文本标记
    public static final int TYPE_TEXT_STRING=201;                // 字符串
    public static final int TYPE_TEXT_INTEGER=202;                // 整数
    public static final int TYPE_TEXT_DECIMAL=203;                // 小数
    
    // 关键字标记
    public static final int TYPE_KEYWORD_CREATE=301;            // create
    public static final int TYPE_KEYWORD_TABLE=302;                // table
    public static final int TYPE_KEYWORD_COLUMN=303;            // column
    public static final int TYPE_KEYWORD_ON=304;                // on
    public static final int TYPE_KEYWORD_IS=305;                // is
    public static final int TYPE_KEYWORD_DEFAULT=306;            // default
    public static final int TYPE_KEYWORD_CHECK=307;                // check
    public static final int TYPE_KEYWORD_OR=308;                // or
    public static final int TYPE_KEYWORD_PRIMARY=309;            // primary
    public static final int TYPE_KEYWORD_KEY=310;                // key
    public static final int TYPE_KEYWORD_COMMENT=311;            // comment
    
    // 字段类型标记
    public static final int TYPE_COLTYPE_CHAR=401;                // char
    public static final int TYPE_COLTYPE_VARCHAR2=402;            // varchar2
    public static final int TYPE_COLTYPE_NVARCHAR2=403;            // nvarchar2
    public static final int TYPE_COLTYPE_NUMBER=404;            // number
    public static final int TYPE_COLTYPE_CLOB=405;                // clob
    public static final int TYPE_COLTYPE_BLOB=406;                // blob
    public static final int TYPE_COLTYPE_TIMESTAMP=407;            // timestamp
    
    // 序列号
    private int sn;
    
    // 文本
    private String text;
    
    // 类型
    private int type;
    
    /**
     * 构造函数一
     * @param txt
     * @param tp
     */
    public Token(String txt,int tp) {
        this.text=txt;
        this.type=tp;
    }
    
    /**
     * 构造函数二
     * @param tp
     * @param txt
     */
    public Token(int tp,String txt) {
        this(txt,tp);
    }
    
    /**
     * 构造函数三
     * @param tp
     * @param ch
     */
    public Token(int tp,char ch) {
        this(tp,String.valueOf(ch));
    }
    
    /**
     * 构造函数四
     * @param ch
     * @param tp
     */
    public Token(char ch,int tp) {
        this(tp,ch);
    }
    
    /**
     * 取得类型的描述
     * @param tp
     * @return
     */
    public static String getTypeDesc(int tp) {
        if(TYPE_SYMBOL_OPEN_PARENTHESIS==tp) {
            return "(";
        }else if(TYPE_SYMBOL_CLOSE_PARENTHESIS==tp) {
            return ")";
        }else if(TYPE_SYMBOL_COMMA==tp) {
            return ",";
        }else if(TYPE_SYMBOL_SEMICOLON==tp) {
            return ";";
        }else if(TYPE_SYMBOL_SINGLE_QUOTA==tp) {
            return "'";
        }else if(TYPE_SYMBOL_DOUBLE_MIDDLE_LINE==tp) {
            return "--";
        }else if(TYPE_SYMBOL_EQUAL==tp) {
            return "=";
        }else if(TYPE_SYMBOL_GREATER_THAN==tp) {
            return ">";
        }else if(TYPE_SYMBOL_GREATER_EQUAL_THAN==tp) {
            return ">=";
        }else if(TYPE_SYMBOL_LESS_THAN==tp) {
            return "<";
        }else if(TYPE_SYMBOL_LESS_EQUAL_THAN==tp) {
            return "<=";
        }else if(TYPE_SYMBOL_DOT==tp) {
            return ".";
        }else if(TYPE_SYMBOL_END_OF_LINE==tp) {
            return "EoL";//End od Line
        }else if(TYPE_TEXT_STRING==tp) {
            return "str";
        }else if(TYPE_TEXT_INTEGER==tp) {
            return "int";
        }else if(TYPE_TEXT_DECIMAL==tp) {
            return "decimal";
        }else if(TYPE_KEYWORD_CREATE==tp) {
            return "create";
        }else if(TYPE_KEYWORD_TABLE==tp) {
            return "table";
        }else if(TYPE_KEYWORD_COLUMN==tp) {
            return "column";
        }else if(TYPE_KEYWORD_ON==tp) {
            return "on";
        }else if(TYPE_KEYWORD_IS==tp) {
            return "is";
        }else if(TYPE_KEYWORD_DEFAULT==tp) {
            return "default";
        }else if(TYPE_KEYWORD_CHECK==tp) {
            return "check";
        }else if(TYPE_KEYWORD_OR==tp) {
            return "or";
        }else if(TYPE_KEYWORD_PRIMARY==tp) {
            return "primary";
        }else if(TYPE_KEYWORD_KEY==tp) {
            return "key";
        }else if(TYPE_KEYWORD_COMMENT==tp) {
            return "comment";
        }else if(TYPE_COLTYPE_CHAR==tp) {
            return "char";
        }else if(TYPE_COLTYPE_VARCHAR2==tp) {
            return "varchar2";
        }else if(TYPE_COLTYPE_NVARCHAR2==tp) {
            return "nvarchar2";
        }else if(TYPE_COLTYPE_NUMBER==tp) {
            return "number";
        }else if(TYPE_COLTYPE_CLOB==tp) {
            return "clob";
        }else if(TYPE_COLTYPE_BLOB==tp) {
            return "blob";
        }else if(TYPE_COLTYPE_TIMESTAMP==tp) {
            return "timestamp";
        }else {
            String msg=String.format("Unrecogniable Type:%d", tp);
            return msg;
        }
    }
    
    public int getSn() {
        return sn;
    }
    public void setSn(int sn) {
        this.sn = sn;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }

    
}
复制代码

 

分词器:

复制代码
package com.hy;

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

/**
 * 分词器
 * 
 * @author hy
 * @since 2022年8月24日
 */
public class Lexer {
    // 标记序列
    private List<Token> tokens;

    /**
     * 构造函数
     * 在其中进行分词
     * 
     * @param txt 待分词的文本
     */
    public Lexer(final String txt) {
        tokens=new ArrayList<>();
        
        final char[] arr=txt.toCharArray();
        final int n=arr.length;
        
        String swallowed = "";
        for(int i=0;i<n;i++) {
            char ch=arr[i];
            
            if(13==ch) {
                // 换行符
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_END_OF_LINE));
            }else if(Character.isWhitespace(ch)) {
                // 空白符
                swallowed=addTxt2Tokens(swallowed);
                continue;
            }else if('('==ch) {
                // (
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_OPEN_PARENTHESIS));
            }else if(')'==ch) {
                // )
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_CLOSE_PARENTHESIS));
            }else if(','==ch) {
                // ,
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_COMMA));
            }else if(';'==ch) {
                // ;
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_SEMICOLON));
            }else if('\''==ch) {
                // '
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_SINGLE_QUOTA));
            }else if('.'==ch) {
                // .
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_DOT));
            }else if('='==ch) {
                // =
                swallowed=addTxt2Tokens(swallowed);
                tokens.add(new Token(ch, Token.TYPE_SYMBOL_EQUAL));
            }else if('>'==ch) {
                
                int next=i+1;
                if(next<n && '='==arr[next]) {
                    // >=
                    swallowed=addTxt2Tokens(swallowed);
                    tokens.add(new Token(">=", Token.TYPE_SYMBOL_GREATER_EQUAL_THAN));
                    i++;// 将序号指向追读位的下一位
                }else {
                    // >
                    swallowed=addTxt2Tokens(swallowed);
                    tokens.add(new Token(ch, Token.TYPE_SYMBOL_GREATER_THAN));
                }
            }else if('<'==ch) {
                
                int next=i+1;
                if(next<n && '='==arr[next]) {
                    // <=
                    swallowed=addTxt2Tokens(swallowed);
                    tokens.add(new Token("<=", Token.TYPE_SYMBOL_LESS_EQUAL_THAN));
                    i++;// 将序号指向追读位的下一位
                }else {
                    // <
                    swallowed=addTxt2Tokens(swallowed);
                    tokens.add(new Token(ch, Token.TYPE_SYMBOL_LESS_THAN));
                }
            }else if('-'==ch) {
                
                int next=i+1;
                if(next<n && '-'==arr[next]) {
                    // --
                    swallowed=addTxt2Tokens(swallowed);
                    tokens.add(new Token("--", Token.TYPE_SYMBOL_DOUBLE_MIDDLE_LINE));
                    i++;// 将序号指向追读位的下一位
                }else {
                    swallowed += ch;
                }
            }else {
                swallowed += ch;
            }
        }
        
        int i=0;
        for(Token tk:tokens) {
            tk.setSn(i++);
        }
    }
    
    /**
     * 判断字符串是否全由空白字符组成
     * 
     * @param s
     * @return
     */
    private static boolean isBlank(String s) {
        final char[] arr=s.toCharArray();
        for(char ch:arr) {
            if(Character.isWhitespace(ch)==false) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 将文本内容添加到标记列表
     * 文本标记可能是关键字、字符串或整数小数
     * 
     * @param txt
     * @return
     */
    private String addTxt2Tokens(String txt) {
        if(isBlank(txt)==false) {
            tokens.add(buildTokenBy(txt));
        }
        
        return "";
    }
    
    /**
     * 以文字构建标记
     * @param txt
     * @return
     */
    private Token buildTokenBy(String txt) {
        if("create".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_CREATE));
        }else if("table".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_TABLE));
        }else if("column".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_COLUMN));
        }else if("on".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_ON));
        }else if("is".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_IS));
        }else if("default".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_DEFAULT));
        }else if("check".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_CHECK));
        }else if("or".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_OR));
        }else if("primary".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_PRIMARY));
        }else if("key".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_KEY));
        }else if("comment".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_KEYWORD_COMMENT));
        }else if("char".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_CHAR));
        }else if("varchar2".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_VARCHAR2));
        }else if("nvarchar2".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_NVARCHAR2));
        }else if("number".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_NUMBER));
        }else if("clob".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_CLOB));
        }else if("blob".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_BLOB));
        }else if("timestamp".equalsIgnoreCase(txt)) {
            return (new Token(txt, Token.TYPE_COLTYPE_TIMESTAMP));
        }else if(isInteger(txt)) {
            return (new Token(txt, Token.TYPE_TEXT_INTEGER));
        }else {
            return (new Token(txt, Token.TYPE_TEXT_STRING));
        }
    }
    
    /**
     * 判断字符串是否全由数字构成
     * 
     * @param s
     * @return
     */
    private static boolean isInteger(String s) {
        final char[] arr=s.toCharArray();
        for(char ch:arr) {
            if(ch<48 || ch>57) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 格式化打印标记,用于调试
     */
    public void printTokens() {
        final String layout="%-20s %-20s %-20s %-20s %s";
        StringBuilder sb=new StringBuilder();
        sb.append(String.format(layout, "#","TEXT","TYPE","DESC","\n"));
        sb.append("------------------------------------------------------\n");
        
        for(Token tk:tokens) {
            String s=String.format(layout, ""+tk.getSn(),tk.getText(),tk.getType(),Token.getTypeDesc(tk.getType()),"\n");
            sb.append(s);
        }
        
        System.out.println(sb.toString());
    }
    
    /**
     * 取得标记列表,用于往解析器传递
     * @return 标记列表
     */
    public List<Token> getTokens() {
        return tokens;
    }
}
复制代码

 

解析器:

复制代码
package com.hy;

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

/**
 * 分析器
 * 
 * @author hy
 * @since 2022年8月25日
 */
public class Parser {
    // 标记列表,由分词器传入
    private List<Token> tokens;
    
    // 当前标记的下标
    private int tkIdx;
    
    // 解析出来的表格
    private List<Table> tables;
    
    /**
     * 构造函数
     * @param tokens
     */
    public Parser(List<Token> tokens) {
        this.tokens=tokens;
        this.tkIdx=0;
        
        tables=new ArrayList<>();
    }
    
    /**
     * 取得Token
     * @return
     */
    private Token fetchToken() {
        if(tkIdx>=tokens.size()) {
            return null;
        }else {
            Token tk=tokens.get(tkIdx);
            tkIdx++;
            return tk;
        }
    }
    
    /**
     * 还回Token
     */
    private void returnToken() {
        if(tkIdx>0) {
            tkIdx--;
        }
    }
    
    /**
     * 运行
     */
    public void run() throws Exception{
        Token token;
        
        for(;;) {
            try {
                token=fetchToken();
                
                if(token==null) {
                    return;
                }else if(Token.TYPE_KEYWORD_CREATE==token.getType()){
                    parseLine_CreateTable();
                }else if(Token.TYPE_TEXT_STRING==token.getType()){
                    returnToken();
                    parseLine_ColumnDef();
                }else if(Token.TYPE_KEYWORD_PRIMARY==token.getType()){
                    parseLine_PrimaryKey();
                }else if(Token.TYPE_SYMBOL_CLOSE_PARENTHESIS==token.getType()){
                    parseLine_EndOfCreateTable();
                }else if(Token.TYPE_KEYWORD_COMMENT==token.getType()){
                    // 下一个应该是on
                    token=fetchToken();
                    if(Token.TYPE_KEYWORD_ON==token.getType()) {
                        // 下一个应该是table/column
                        token=fetchToken();
                        if(Token.TYPE_KEYWORD_TABLE==token.getType()) {
                            parseLine_CommentTable();
                        }else if(Token.TYPE_KEYWORD_COLUMN==token.getType()) {
                            parseLine_CommentColumn();
                        }else {
                            throw new Exception(buildErrmsg("table or column",token));
                        }
                    }else {
                        throw new Exception(buildErrmsg("on",token));
                    }
                }else if(Token.TYPE_SYMBOL_DOUBLE_MIDDLE_LINE==token.getType()) {
                    // 遇到注释行直接读到行结束符号
                    do {
                        token=fetchToken();
                    }while(Token.TYPE_SYMBOL_END_OF_LINE!=token.getType());
                }
            }catch(Exception ex) {
                ex.printStackTrace();
                continue;
            }
        }
    }
    
    /**
     * 得到表格的描述性文字
     * @return
     */
    public String getTablesDesc() {
        StringBuilder sb=new StringBuilder();
        
        for(Table tb:tables) {
            sb.append(tb.getName()+" "+tb.getRemark()+"\n");
            
            for(Column col:tb.getColumns()) {
                String msg=String.format("    name:%s type:%s precise:%s pk:%b remark:%s\n", 
                        col.getName(),
                        col.getType(),
                        col.getPrecise(),
                        col.isPk(),
                        col.getRemark());
                sb.append(msg);
            }
            
            sb.append("\n");
        }
        
        return sb.toString();
    }
    
    /**
     * 解析表注释行
     * @throws Exception
     */
    private void parseLine_CommentTable() throws Exception{
        // 第一个应当是表名
        Token token=fetchToken();
        
        if(Token.TYPE_TEXT_STRING==token.getType()) {
            final String tableName=token.getText();
            
            // 下一个应当是is
            token=fetchToken();
            if(Token.TYPE_KEYWORD_IS==token.getType()) {
                
                // 下一个应当是'
                token=fetchToken();
                if(Token.TYPE_SYMBOL_SINGLE_QUOTA==token.getType()) {
                    // 下一个应当是str
                    token=fetchToken();
                    if(Token.TYPE_TEXT_STRING==token.getType()) {
                        final String tableRemark=token.getText();
                        
                        // 下一个应当是'
                        token=fetchToken();
                        if(Token.TYPE_SYMBOL_SINGLE_QUOTA==token.getType()) {
                            // 下一个应当是;
                            token=fetchToken();
                            if(Token.TYPE_SYMBOL_SEMICOLON==token.getType()) {
                                //System.out.println("表"+tableName+"的注释是"+tableRemark);
                                
                                for(Table tb:tables) {
                                    if(tableName.equalsIgnoreCase(tb.getName())) {
                                        tb.setRemark(tableRemark);
                                    }
                                }
                                
                                // 结束
                                return;
                            }else {
                                throw new Exception(buildErrmsg(";",token));
                            }
                        }else {
                            throw new Exception(buildErrmsg("\'",token));
                        }
                    }else {
                        throw new Exception(buildErrmsg("str",token));
                    }
                }else {
                    throw new Exception(buildErrmsg("\'",token));
                }
            }else {
                throw new Exception(buildErrmsg("is",token));
            }
        }else {
            throw new Exception(buildErrmsg("str",token));
        }
    }
    
    /**
     * 解析列注释行
     * @throws Exception
     */
    private void parseLine_CommentColumn() throws Exception{
        // 第一个应当是表名
        Token token=fetchToken();
        
        if(Token.TYPE_TEXT_STRING==token.getType()) {
            final String tableName=token.getText();
            
            // 下一个应当是.
            token=fetchToken();
            if(Token.TYPE_SYMBOL_DOT==token.getType()) {
                // 下一个应当是字段名
                token=fetchToken();
                if(Token.TYPE_TEXT_STRING==token.getType()) {
                    final String columnName=token.getText();
                    
                    // 下一个应当是is
                    token=fetchToken();
                    if(Token.TYPE_KEYWORD_IS==token.getType()) {
                        
                        // 下一个应当是'
                        token=fetchToken();
                        if(Token.TYPE_SYMBOL_SINGLE_QUOTA==token.getType()) {
                            // 下一个应当是str
                            token=fetchToken();
                            if(Token.TYPE_TEXT_STRING==token.getType()) {
                                final String columnRemark=token.getText();
                                
                                // 下一个应当是'
                                token=fetchToken();
                                if(Token.TYPE_SYMBOL_SINGLE_QUOTA==token.getType()) {
                                    // 下一个应当是;
                                    token=fetchToken();
                                    if(Token.TYPE_SYMBOL_SEMICOLON==token.getType()) {
                                        //System.out.println("表"+tableName+"的字段"+columnName+"的注释是"+columnRemark);
                                        for(Table tb:tables) {
                                            if(tableName.equalsIgnoreCase(tb.getName())) {
                                                List<Column> columns=tb.getColumns();
                                                for(Column col:columns) {
                                                    if(col.getName().equalsIgnoreCase(columnName)) {
                                                        col.setRemark(columnRemark);
                                                    }
                                                }
                                            }
                                        }
                                        
                                        // 结束
                                        return;
                                    }else {
                                        throw new Exception(buildErrmsg(";",token));
                                    }
                                }else {
                                    throw new Exception(buildErrmsg("\'",token));
                                }
                            }else {
                                throw new Exception(buildErrmsg("str",token));
                            }
                        }else {
                            throw new Exception(buildErrmsg("\'",token));
                        }
                    }else {
                        throw new Exception(buildErrmsg("is",token));
                    }
                }else {
                    throw new Exception(buildErrmsg("str",token));
                }
            }else {
                throw new Exception(buildErrmsg(".",token));
            }
        }else {
            throw new Exception(buildErrmsg("str",token));
        }
    }
    
    /**
     * 解析主键行
     * @throws Exception
     */
    private void parseLine_PrimaryKey() throws Exception{
        // 下一个Token应该是key
        Token token=fetchToken();
        
        if(Token.TYPE_KEYWORD_KEY==token.getType()) {
            // 下一个Token应该是(
            token=fetchToken();
            
            if(Token.TYPE_SYMBOL_OPEN_PARENTHESIS==token.getType()) {
                // 下一个Token应该是string
                token=fetchToken();
                
                if(Token.TYPE_TEXT_STRING==token.getType()) {
                    final String primaryKeyColumn=token.getText();
                    
                    
                    // 最后一个Token应该是)
                    token=fetchToken();
                    if(Token.TYPE_SYMBOL_CLOSE_PARENTHESIS==token.getType()) {
                        // 结束了
                        //System.out.println("primary Key column:"+primaryKeyColumn);
                        Table lastTb=tables.get(tables.size()-1);
                        List<Column> columns=lastTb.getColumns();
                        for(Column col:columns) {
                            if(col.getName().equalsIgnoreCase(primaryKeyColumn)) {
                                col.setPk(true);
                            }
                        }
                        
                        return;
                    }else {
                        throw new Exception(buildErrmsg(")",token));
                    }
                    
                }else {
                    throw new Exception(buildErrmsg("(",token));
                }
            }else {
                throw new Exception(buildErrmsg("(",token));
            }
        }else {
            throw new Exception(buildErrmsg("key",token));
        }
    }
    
    /**
     * 解析字段定义行
     * @throws Exception
     */
    private void parseLine_ColumnDef() throws Exception{
        // 回退第一个Token应该是文本
        Token token=fetchToken();
        
        if(Token.TYPE_TEXT_STRING==token.getType()) {
            final String columnName=token.getText();
            //System.out.println("Column name:"+columnName);
            
            // 下一个Token应该是字段类型
            token=fetchToken();
            if(     Token.TYPE_COLTYPE_CHAR==token.getType() ||
                    Token.TYPE_COLTYPE_VARCHAR2==token.getType() ||
                    Token.TYPE_COLTYPE_NVARCHAR2==token.getType() ||
                    Token.TYPE_COLTYPE_NUMBER==token.getType() ||
                    Token.TYPE_COLTYPE_CLOB==token.getType() ||
                    Token.TYPE_COLTYPE_BLOB==token.getType() ||
                    Token.TYPE_COLTYPE_TIMESTAMP==token.getType() ) {
                
                final String columnType=token.getText();
                //System.out.println("Column type:"+columnType);
                
                // 下一个Token应该是(
                token=fetchToken();
                if(Token.TYPE_SYMBOL_OPEN_PARENTHESIS==token.getType()) {
                    
                    // 下一个Token应该是数字
                    token=fetchToken();
                    if(Token.TYPE_TEXT_INTEGER==token.getType()) {
                        String columnPrecise=token.getText();
                        
                        // 下一个Token可能是)或.
                        token=fetchToken();
                        if(Token.TYPE_SYMBOL_CLOSE_PARENTHESIS==token.getType()) {
                            // 是)的话,下一个应该是,
                            token=fetchToken();
                            if(Token.TYPE_SYMBOL_COMMA==token.getType()) {
                                //System.out.println("Column precise:"+columnPrecise);
                                Column newColumn=new Column(columnName,columnType);
                                newColumn.setPrecise(columnPrecise);
                                Table lastTb=tables.get(tables.size()-1);
                                lastTb.getColumns().add(newColumn);
                                
                                return;
                            }else {
                                throw new Exception(buildErrmsg(",",token));
                            }
                        }else if(Token.TYPE_SYMBOL_COMMA==token.getType()) {
                            // 是.的话,下一个应该是数字
                            token=fetchToken();
                            if(Token.TYPE_TEXT_INTEGER==token.getType()) {
                                columnPrecise+=","+token.getText();// 补全精度
                                
                                // 下一个应该是)
                                token=fetchToken();
                                if(Token.TYPE_SYMBOL_CLOSE_PARENTHESIS==token.getType()) {
                                    
                                    // 最后一个应该是,
                                    token=fetchToken();
                                    if(Token.TYPE_SYMBOL_COMMA==token.getType()) {
                                        //System.out.println("Column precise:"+columnPrecise);
                                        
                                        Column newColumn=new Column(columnName,columnType);
                                        newColumn.setPrecise(columnPrecise);
                                        Table lastTb=tables.get(tables.size()-1);
                                        lastTb.getColumns().add(newColumn);
                                        
                                        return;
                                    }else {
                                        throw new Exception(buildErrmsg(",",token));
                                    }
                                }else {
                                    throw new Exception(buildErrmsg(")",token));
                                }
                            }else {
                                throw new Exception(buildErrmsg("int",token));
                            }
                            
                        }else {
                            throw new Exception(buildErrmsg(") or ,",token));
                        }
                    }else {
                        throw new Exception(buildErrmsg("int",token));
                    }
                }else {
                    throw new Exception(buildErrmsg("(",token));
                }
            }else {
                throw new Exception(buildErrmsg("column type",token));
            }
        }else {
            throw new Exception(buildErrmsg("str",token));
        }
    }
    
    /**
     * 处理建表结束行
     * @throws Exception
     */
    private void parseLine_EndOfCreateTable() throws Exception{
        // 下一个Token应该是分号
        Token token=fetchToken();
        
        if(Token.TYPE_SYMBOL_SEMICOLON==token.getType()) {
            return;
        }else {
            throw new Exception(buildErrmsg(";",token));
        }
    }
    
    /**
     * 处理建表行
     * @throws Exception
     */
    private void parseLine_CreateTable() throws Exception{
        // 下一个Token应该是table关键字
        Token token=fetchToken();
        if(Token.TYPE_KEYWORD_TABLE==token.getType()) {
            // 下一个Token应该是文本
            token=fetchToken();
            if(Token.TYPE_TEXT_STRING==token.getType()) {
                String tableName=token.getText();
                
                
                //下一个Token应该是左括号
                token=fetchToken();
                if(Token.TYPE_SYMBOL_OPEN_PARENTHESIS==token.getType()) {
                    // 读到左括号则建表行处理结束
                    //System.out.println("表:"+tableName);
                    this.tables.add(new Table(tableName));
                    
                    return;
                }else {
                    throw new Exception(buildErrmsg("(",token));
                }
            }
            else {
                throw new Exception(buildErrmsg("str",token));
            }
        }else {
            throw new Exception(buildErrmsg("table",token));
        }
    }
    
    private String buildErrmsg(String expect,Token tk) {
        String errmsg=String.format("expect:‘%s’,actual:‘%s’,sn=‘%d’", expect,tk.getText(),tk.getSn());
        return errmsg;
    }
}
复制代码

 

实体表类:

复制代码
package com.hy;

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

/**
 * 表实体类
 * 
 * @author hy
 * @since 2022年8月25日
 */
public class Table {
    private String name;
    private String remark;
    List<Column> columns;
    
    public Table(String name) {
        this.name=name;
        columns=new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public List<Column> getColumns() {
        return columns;
    }

    public void setColumns(List<Column> columns) {
        this.columns = columns;
    }
}
复制代码

 

实体列类:

复制代码
package com.hy;

/**
 * 表字段实体类
 * 
 * @author hy
 * @since 2022年8月25日
 */
public class Column {
    private String name;
    private String type;
    private String precise;
    private boolean pk=false;
    private String remark;
    
    public Column(String name) {
        this.name=name;
    }
    
    public Column(String name,String type) {
        this.name=name;
        this.type=type;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getPrecise() {
        return precise;
    }
    public void setPrecise(String precise) {
        this.precise = precise;
    }
    public boolean isPk() {
        return pk;
    }
    public void setPk(boolean pk) {
        this.pk = pk;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
}
复制代码

 

【实际解析结果】

复制代码
emp01 雇员表
    name:id type:number precise:12 pk:true remark:ID
    name:name type:nvarchar2 precise:20 pk:false remark:雇员名称
    name:age type:number precise:3 pk:false remark:年龄
    name:salary type:number precise:10,2 pk:false remark:薪水
    name:dept_id type:number precise:12 pk:false remark:所在部门ID

dept01 部门表
    name:id type:number precise:12 pk:true remark:ID
    name:name type:nvarchar2 precise:20 pk:false remark:部门名称
复制代码

可以说,表定义的信息都都取出来了。

 

【后记】

这个解析难度和工作量都不大,适合上手热身。

当然只看结果的话,取表信息也可以把表建出来以后用Metadata或是字典表去取,但那样就不是文本解析了。

END

posted @   逆火狂飙  阅读(655)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2021-08-24 【oracle】查本当连续无重复的序列有无重复,重复多少个,再清除重复项
2021-08-24 就Sql解析絮叨几句
2021-08-24 【作品】SqlResolver介绍下载交流页
2019-08-24 Let a mthod in RestControl return a json string
2019-08-24 【Canvas与绳结】双锁结
2019-08-24 spring cloud microservice provider and consumer
2019-08-24 How to solve the error "Field service in com.xx.xxx.xxxx required a bean of type 'com.aa.bb.cc' that could not be found."
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示