【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
分类:
Java.Compiler
, 我的软件作品
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需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."