c# 怎样能写个sql的解析器
c# 怎样能写个sql的解析器
本示例主要是讲明sql解析的原理,真实的源代码下查看 sql解析器源代码
详细示例DEMO 请查看demo代码
前言
阅读本文需要有一定正则表达式基础 正则表达式基础教程 ,和编译原理的基础。有使用过VUE的伙伴可能知道vue是自定了模版解析编译器的,vue用的是标准的AST语法树统计,如果对语法树不了了解的请查看 什么是AST抽像语法树
本示例介绍的是参考编译原理 词法分析->语法分析->构建AST语法树->解析成目标sql 的流程来实现
示例
sqlserver 的一条查询语句
select a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a
假如我们要将以上代码进行格式化成以下方式
select [a].[UniqueCode],[a].[BarCode],[a].[CategoryId] from [GD_UniqueCodeInfo] as [a]
分析
首先我们来分析一下这个语句有什么特点。
找关键词
这个sql语法有三个关键词如select
,from
,as
找结构
有字段信息a.UniqueCode,a.BarCode,a.CategoryId
,有表名信息GD_UniqueCodeInfo
还有 被重命名的表信息a
这些信息可能符合命名规范可能用些不符合,那么在解析时都要进行检测出来标识符
在生成的目标sql语句中有[] 这个的作用主要是万一字段名出现与关键词有相同的字段名称能进行正常识别
开始
首先我们先创建两个c#解析正则表达式的方法
这个方法就是可以将正则表达式中的匹配数据提出来返回一个字典数据
public static Dictionary<string, string> RegexGrp(string regex,string text)
{
Regex _regex = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
Dictionary<string, string> _dic = new Dictionary<string, string>();
Match _match = _regex.Match(text);
while (_match.Success)
{
foreach (string name in _regex.GetGroupNames())
{
if(!_dic.ContainsKey(name))
_dic.Add(name, _match.Groups[_regex.GroupNumberFromName(name)].Value);
}
_match = _match.NextMatch();
}
return _dic;
}
检测正则表达工是否正确匹配
public static bool RegexMatch(string regex, string text)
{
Regex _regex = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
Match _match = _regex.Match(text);
return _match.Success;
}
第一步 先检测这个sql语句是否是一个查询语句
正则代码:^\s*(?<cmd>select)\s+(?<field>[\w\s\S]+(?=\bfrom\b))(?:\bfrom\b)(?<from>(?:[\s]+)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+)\s*[\s\w\S]*)
那么我们来验证下
通过把要解析的SQL语句放入测试工具中运行
在右下方的区域通过正则匹配已经把该语句结构已经拆解出来了
cmd:select
field:a.UniqueCode,a.BarCode,a.CategoryId
tab:GD_UniqueCodeInfo
一下就把SQL语句结构化出来了,有匹配结果说明是一个正常的sql语句
第二步 通过代码获取结构信息
string sql="select a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a";
Dictionary<string, string> dic =RegexGrp(@"^\s*(?<cmd>select)\s+(?<field>[\w\s\S]+(?=\bfrom\b))(?:\bfrom\b)(?<from>(?:[\s]+)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+)\s*[\s\w\S]*)",sql);
if(dic.ConstainsKey("cmd"))
{
// 说明匹配成功
Console.Write(dic["cmd"]);
}
拆解select 后要把select 替换为空剩余的sql 为 a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a
第三步 拆解字段
正则表达式:^\s*(?<field>[\w\s\S]*?(?=\bfrom\b))
两通过测试工具测试一下
那么可以通过代码获取出来
string sql="a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a";
Dictionary<string, string> dic =RegexGrp(@"^\s*(?<field>[\w\s\S]*?(?=\bfrom\b))",sql);
if (dic.ContainsKey("field"))
{
//说明匹配成功
}
字段是有多个的 还要单独拆解成一个一个的字段,拆解字段的这个就不详细描述了,可以继续用正则表达式也可以用Split(',') 进行分拆
如
var _field=dic["field"];
var fields=_field.Split(',')
拆解完字段后 剩余的sql:from GD_UniqueCodeInfo as a
拆解from
正则表达式:^\s*(?:\bfrom\b)(?<from>(?:[\s]+)(?<table>(?:[\s]*)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+))\s*(?:\bas\b\s*(?<asname>[\w]+))?\s*)
通过该正则表达式可以拆解出 通过 as 重命名的表
下面通过正则表达式工具测试一下
那么通过以下代码来获取
string sql="from GD_UniqueCodeInfo as a";
Dictionary<string, string> dic =RegexGrp(@"^\s*(?:\bfrom\b)(?<from>(?:[\s]+)(?<table>(?:[\s]*)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+))\s*(?:\bas\b\s*(?<asname>[\w]+))?\s*)",sql);
if (dic.ContainsKey("tab"))
{
//说明匹配成功
}
此时 就通过正则表达式拆解完成,但还需要对它进行结构化
以下是代码截图片段
请查看demo代码
c# 怎样能写个sql的解析器的更多相关文章
- atitit.java解析sql语言解析器解释器的实现
atitit.java解析sql语言解析器解释器的实现 1. 解析sql的本质:实现一个4gl dsl编程语言的编译器 1 2. 解析sql的主要的流程,词法分析,而后进行语法分析,语义分析,构建sq ...
- 简单sql字段解析器实现参考
用例:有一段sql语句,我们需要从中截取出所有字段部分,以便进行后续的类型推断,请给出此解析方法. 想来很简单吧,因为 sql 中的字段列表,使用方式有限,比如 a as b, a, a b... 1 ...
- kotlin 写的一个简单 sql 查询解析器
package com.dx.efuwu.core import org.apache.commons.lang.StringUtils import java.sql.PreparedStateme ...
- C++写一个简单的解析器(分析C语言)
该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...
- Spring boot中自定义Json参数解析器
转载请注明出处... 一.介绍 用过springMVC/spring boot的都清楚,在controller层接受参数,常用的都是两种接受方式,如下 /** * 请求路径 http://127.0. ...
- SpringBoot自定义参数解析器
一.背景 平常经常用 @RequestParam注解来获取参数,然后想到我能不能写个自己注解获取请求的ip地址呢?就像这样 @IP String ip 二.分析 于是开始分析 @RequestPara ...
- Python 之父撰文回忆:为什么要创造 pgen 解析器?
花下猫语: 近日,Python 之父在 Medium 上开通了博客,并发布了一篇关于 PEG 解析器的文章(参见我翻的 全文译文).据我所知,他有自己的博客,为什么还会跑去 Medium 上写文呢?好 ...
- 非标准的xml解析器的C++实现:一、思考基本数据结构的设计
前言: 我在C++项目中使用xml作为本地简易数据管理,到目前为止有5年时间了,从最初的全文搜索标签首尾,直到目前项目中实际运用的类库细致到已经基本符合w3c标准,我一共写过3次解析器,我自己并没有多 ...
- SQL 里解析 XML 格式 字段 信息
DECLARE @ItemMessage XML ),zje ),yfje ),bcje ),URL ),Remark )) SET @ItemMessage=N'<List> <i ...
随机推荐
- KotlinMall实战之注册部分MVP架构配置
包目录如下: ①BaseView部分:基本的回调 interface BaseView { fun showLoading() fun hideLoading() fun onError()} ②Ba ...
- python基础练习题(题目 求s=a+aa+aaa+aaaa+aa…a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加),几个数相加由键盘控制)
day11 --------------------------------------------------------------- 实例018:复读机相加 题目 求s=a+aa+aaa+aaa ...
- [AcWing 756] 蛇形矩阵
点击查看代码 #include<iostream> using namespace std; const int N = 110; int n, m; int dx[] = {-1, 0, ...
- python+pytest接口自动化(15)-日志管理模块loguru简介
python自带日志管理模块logging,使用时可进行模块化配置,详细可参考博文Python日志采集(详细). 但logging配置起来比较繁琐,且在多进行多线程等场景下使用时,如果不经过特殊处理, ...
- MyCat安装和基本配置
安装包下载 下载地址:http://dl.mycat.org.cn/ 我只这里下的是1.6Linux安装包:http://dl.mycat.org.cn/1.6.7.6/20220419132943/ ...
- RESTFul是一种风格
只要符合RESTFul风格的,都可以叫做使用了RESTFul架构,一般的网站里传数据,都是用的?a=1&b=2...如果是RESTFul风格的话,就会是/a/1/b/2..类似于这样的方式来传 ...
- mybatis plus 的 ActiveRecord 模式
实体类继承 Model public class Test extends Model<Test> implements Serializable {} 就可以 new Test().in ...
- 【多线程】创建线程方式二:实现Runnable接口
创建线程方式二:实现Runnable接口 代码示例: /** * @Description 实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口实现类,调用start方法 * ...
- 832. Flipping an Image - LeetCode
Question 832. Flipping an Image Solution 题目大意:将1列与最后n列对换,2列与n-1列对换-然后再将每个元素取反 思路:遍历二维数组的左半边,对每个元素先做对 ...
- 【freertos】008-内存管理
前言 本章主要讲解内部存储空间(RAM)的管理. 详细分析heap5方案. 参考: 李柱明博客 https://freertos.blog.csdn.net/article/details/51606 ...