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)
今天写了一个可以测试并发数和运行次数的压力测试代码 介绍一下为什么会写这么一个工具. 介绍一个这个工具怎么用的. 背景 最近在开发CoapServer端,以及模拟设备侧发送数据调用开发好的CoapSe ...
- C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解
系列目录 [已更新最新开发文章,点击查看详细] 在我的博客<C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解>最后列出了 Fil ...
- Tensorflow 窗口时间序列数据的处理
Tensorflow 时间序列数据的处理 数据集简介 数据来源:Kaggle Ubiquant Market Prediction 数据集描述了多个投资项目在一个时间序列下的300个匿名特征(&quo ...
- IDEA2021.2安装lombok插件(借鉴前辈)
lomhok下载地址: https://plugins.jetbrains.com/plugin/6317-lombok/versions CSDN关注斧头湖懒客 一,下载lombok插件我这里下载的 ...
- 初次接触Java感受
认真开始研究了idea后端开发环境 感触很深,突然觉得自己不能再一天的颓废下去,认真找点事情做一做,毕竟自己还是一张白纸,趁着自己年纪轻轻 经过一周的摸索自己努力了还不够,心里多么渴望自己身边的人能够 ...
- [题解] XOR Problem
题目大意 对于一个整数序列 \(a_{0...5}\),我们定义它的价值为: \(f(a)=max(|a_0-a_3|,|a_1-a_4|,|a_2-a_5|)\oplus a_0 \oplus a_ ...
- .NET混合开发解决方案8 WinForm程序中通过设置固定版本运行时的BrowserExecutableFolder属性集成WebView2控件
系列目录 [已更新最新开发文章,点击查看详细] 在我的博客<.NET混合开发解决方案7 WinForm程序中通过NuGet管理器引用集成WebView2控件>中介绍了WinForm ...
- re模块,正则表达式起别名和分组机制,collections模块,time与datetime模块,random模块
re模块和正则表达式别名和分组机制 命名分组 (1)分组--可以让我们从文本内容中提取指定模式的部分内容,用()来表示要提取的分组,需要注意的是分组 是在整个文本符合指定的正则表达式前提下进行的进一步 ...
- mongodb 复杂查询
记录一下工作中用到的 mongodb 复杂查询 aggregate 筛选 === 等于 { $match: { name: "bob" } } !== 不等于 { $match: ...
- 485. Max Consecutive Ones - LeetCode
Question 485. Max Consecutive Ones Solution 题目大意:给一个数组,取连续1的最大长度 思路:遍历数组,连续1就加1,取最大 Java实现: public i ...