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 ...
随机推荐
- Java语言学习day39--8月14日
今日内容介绍1.Map接口2.模拟斗地主洗牌发牌 ###01Map集合概述 A:Map集合概述: 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形 ...
- 2021.08.09 P6037 Ryoku的探索(基环树)
2021.08.09 P6037 Ryoku的探索(基环树) P6037 Ryoku 的探索 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.树的性质 2.基环树的性质 ...
- 基于深度学习的人脸性别识别系统(含UI界面,Python代码)
摘要:人脸性别识别是人脸识别领域的一个热门方向,本文详细介绍基于深度学习的人脸性别识别系统,在介绍算法原理的同时,给出Python的实现代码以及PyQt的UI界面.在界面中可以选择人脸图片.视频进行检 ...
- SpringCloudAlibaba微服务docker容器打包和部署示例实战
概述 我们使用前面<SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(中)>的两个微服务示例,分别是库存微服务和订单微服务,基于Nacos注册中心和配置 ...
- 使用 GO-CQHttp或mirai框架 搭建QQ的机器人
我的博客 Go-CQHttp搭建QQ机器人 官方文档在这-->ATRU官方文档 Go-CQHttp + Atri 使用Linux系统部署 需求 服务器一台/带有Linux的机器 Python环境 ...
- 使用aspnetcore前后端分离开发,你一定要知道这个
前言 用过Vue单页面应用开发的,一定都知道Vue-router这个路由组件,它支持hash和history两种模式. HTML5 History 模式 vue-router 默认 hash 模式 - ...
- 让交互更加生动!有意思的鼠标跟随 3D 旋转动效
今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现: 简单分析一下,这个交互效果主要有两个核心: 借助了 CSS 3D 的能力 元素的旋转需要和鼠标的移动相结合 本文,就将讲述如何使用纯 ...
- C++基础-1-内存管理(全局区、堆区、栈区)
1. 内存管理 1.1 全局区 1 #include<iostream> 2 using namespace std; 3 4 // 全局变量 5 int g_a = 10; 6 int ...
- this-4
ES6函数里的this指的是定义这个函数时外层代码的this,可以理解为:1.ES6箭头函数没有自己的this:2.ES6箭头函数的this是外层代码(定义时,非执行时,也就是词法作用域)this的引 ...
- VsCode[Git] | 配置Gitee和Github | 不使用全局用户名和邮箱
(VsCode[Git] | 配置Gitee和Github | 不使用全局用户名和邮箱 | 2021-04-11) 目录 一 .安装Git / VsCode配置Git / Win10系统 二.Git配 ...