本篇文章為大家帶來了關於java的相關知識,主要介紹了java詞法分析器DDL遞歸應用詳解,有需要的朋友可以藉鑑參考下,下面一起來看一下,希望對大家有幫助。
推薦學習:《java影片教學》
既然沒有現成的工具那就自己寫一個吧
考慮到我們主要是用PyCharm
開發,剛好jetbrains
也提供了SDK
用於開發插件,所以UI
層面可以不用額外考慮了。
使用流程很簡單,只需要匯入DDL
語句就可以產生Python
所需的Model
程式碼。
例如導入以下DDL:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(20) DEFAULT NULL COMMENT '用户名', `password` varchar(100) DEFAULT NULL COMMENT '密码', `roleId` int(11) DEFAULT NULL COMMENT '角色ID', PRIMARY KEY (`id`), ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
便會產生對應的Python 程式碼:
class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True, autoincrement=True) userName = db.Column(db.String) # 用户名 password = db.Column(db.String) # 密码 roleId = db.Column(db.Integer) # 角色ID
仔細對比原始檔及目標程式碼會很容易找出規律,無非就是解析出表名、欄位、及欄位的屬性(是否為主鍵、型別、長度),最後再轉換為Python
所需的範本即可。
在我動手之前我認為是非常簡單的,無非就是解析字串,但實際上手後發現不是那麼回事;主要是有以下幾個問題:
總結一句話,如何透過一系列規則識別出一段字串中的關鍵訊息,這同樣也是 MySQL Server 所做的事情。
在開始真正解析DDL 之前,先來看看下一段簡單的腳本如何解析:
##按照我們平常開發的經驗,這條語句分為以下幾部分:x = 20
表示變數
表示賦值符號
表示賦值結果
VAR xGE =VAL 100這個解析過程在編譯原理中稱為」詞法解析“,可能大家聽到編譯原理這幾個字就頭大(我也是);對於剛才那段腳本我們可以寫一個非常簡單的詞法解析器來產生這樣的結果。 狀態遷移再開始之前先捋一下思路,可以看到上文的結果中透過
VAR表示變數、
GE表示賦值符號”=“、
VAL表示賦值結果,現在需要重點記住這三個狀態。
狀態。
#狀態。
public class Result{ public TokenType tokenType ; public StringBuilder text = new StringBuilder(); }先定義了一個結果類,收集最終的解析結果;其中的
TokenType就對應了圖中的三種狀態,簡單的用枚舉值來表示。
public enum TokenType { INIT, VAR, GE, VAL }首先對應到第一張圖:初始化狀態。 需要對目前解析的字元定義一個
TokenType:
case,在不同的
case中判斷是否要跳到其他狀態(進入
INIT狀態後會重新產生狀態)。
x = 20:
VAR狀態,接著下一個字元為空格,自然在38 行中重新進入初始狀態,導致再次確定下一個字元
=進入
GE狀態。
ab = 30:
第一個字元為a 也是進入
VAR狀態,第二個字元為b,依然為字母,所以進入36 行,狀態不會改變,同時將b 這個字元追加進來;後續步驟就和上一個例子一致了。
简单的解析完成后来看看DDL
这样的脚本应当如何解析:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(20) DEFAULT NULL COMMENT '用户名', `password` varchar(100) DEFAULT NULL COMMENT '密码', `roleId` int(11) DEFAULT NULL COMMENT '角色ID', PRIMARY KEY (`id`), ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
原理类似,首先还是要看出规律(也就是语法):
CREATE TABLE
开头。)
结尾。根据我们需要解析的数据种类,我这里定义了这个枚举:
然后在初始化类型时进行判断赋值:
由于需要解析的数据不少,所以这里的判断条件自然也就多了。
针对于DDL
的语法规则,我们这里还有需要有特殊处理的地方;比如解析具体字段信息时如何关联起来?
举个例子:
`userName` varchar(20) DEFAULT NULL COMMENT '用户名', `password` varchar(100) DEFAULT NULL COMMENT '密码',
这里我们解析出来的数据得有一个映射关系:
所以我们只能一个字段的全部信息解析完成并且关联好之后才能解析下一个字段。
于是这里我采用了递归的方式进行解析(不一定是最好的,欢迎大家提出更优的方案)。
} else if (value == '`' && pStatus == Status.BASE_INIT) { result.tokenType = DDLTokenType.FI; result.text.append(value); }
当当前字符为 ”`“ 符号时,将状态置为 “FI”(FieldInfo),同时当解析到为 “,” 符号时便进入递归处理。
可以理解为将这一段字符串单独提取出来处理:
`userName` varchar(20) DEFAULT NULL COMMENT '用户名',
接着再将这段字符递归调用当前方法再次进行解析,这时便按照字段名称、类型、长度、注释的规则解析即可。
同时既然存在递归,还需要将子递归的数据关联起来,所以我在返回结果中新增了一个pid
的字段,这个也容易理解。
默认值为 0,一旦递归后便自增 +1,保证每次递归的数据都是唯一的。
用同样的方法在解析主键时也是先将整个字符串提取出来:
PRIMARY KEY (`id`)
只不过是 “P” 打头 “)” 结尾。
} else if (value == 'P' && pStatus == Status.BASE_INIT) { result.tokenType = DDLTokenType.P_K; result.text.append(value); }
也是将整段字符串递归解析,再递归的过程中进行状态切换P_K ---> P_K_V
最终获取到主键。
所以通过对刚才那段DDL
解析得到的结果如下:
这样每个字段也通过了pid
进行了区分关联。
所以现在只需要对这个词法解析器进行封装,便可以提供一个简单的API
来获取表中的数据了。
推荐学习:《java视频教程》
以上是詳細解析java詞法分析器DDL遞歸應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!