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]

分析

首先我们来分析一下这个语句有什么特点。

  1. 找关键词

    这个sql语法有三个关键词如select ,from,as

  2. 找结构

    有字段信息a.UniqueCode,a.BarCode,a.CategoryId,有表名信息GD_UniqueCodeInfo 还有 被重命名的表信息a 这些信息可能符合命名规范可能用些不符合,那么在解析时都要进行检测出来

  3. 标识符

    在生成的目标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的解析器的更多相关文章

  1. atitit.java解析sql语言解析器解释器的实现

    atitit.java解析sql语言解析器解释器的实现 1. 解析sql的本质:实现一个4gl dsl编程语言的编译器 1 2. 解析sql的主要的流程,词法分析,而后进行语法分析,语义分析,构建sq ...

  2. 简单sql字段解析器实现参考

    用例:有一段sql语句,我们需要从中截取出所有字段部分,以便进行后续的类型推断,请给出此解析方法. 想来很简单吧,因为 sql 中的字段列表,使用方式有限,比如 a as b, a, a b... 1 ...

  3. kotlin 写的一个简单 sql 查询解析器

    package com.dx.efuwu.core import org.apache.commons.lang.StringUtils import java.sql.PreparedStateme ...

  4. C++写一个简单的解析器(分析C语言)

    该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...

  5. Spring boot中自定义Json参数解析器

    转载请注明出处... 一.介绍 用过springMVC/spring boot的都清楚,在controller层接受参数,常用的都是两种接受方式,如下 /** * 请求路径 http://127.0. ...

  6. SpringBoot自定义参数解析器

    一.背景 平常经常用 @RequestParam注解来获取参数,然后想到我能不能写个自己注解获取请求的ip地址呢?就像这样 @IP String ip 二.分析 于是开始分析 @RequestPara ...

  7. Python 之父撰文回忆:为什么要创造 pgen 解析器?

    花下猫语: 近日,Python 之父在 Medium 上开通了博客,并发布了一篇关于 PEG 解析器的文章(参见我翻的 全文译文).据我所知,他有自己的博客,为什么还会跑去 Medium 上写文呢?好 ...

  8. 非标准的xml解析器的C++实现:一、思考基本数据结构的设计

    前言: 我在C++项目中使用xml作为本地简易数据管理,到目前为止有5年时间了,从最初的全文搜索标签首尾,直到目前项目中实际运用的类库细致到已经基本符合w3c标准,我一共写过3次解析器,我自己并没有多 ...

  9. SQL 里解析 XML 格式 字段 信息

    DECLARE @ItemMessage XML ),zje ),yfje ),bcje ),URL ),Remark )) SET @ItemMessage=N'<List> <i ...

随机推荐

  1. Codeforces Round #754 (Div. 2), problem: (A) A.M. Deviation泪目 万万没想到狂wa是因为这

    Problem - A - Codeforces 题目 题意很简单每次操作可以使得a1 a2  a3任意两个数分别+1  -1 求最后使得a+c-2b绝对值的最小值 BUG就是最后忽略了-2和2这一点 ...

  2. Codeforces Round #703 (Div. 2)__ B. Eastern Exhibition__ 纯纯的思维

    原题链接https://codeforces.com/contest/1486/problem/B 题目 解题思路 这是个思维题,  算是货仓选址的变式, 想要到达各个点距离最小,我们的目标可以化为先 ...

  3. JavaScript基础第02天笔记

    JavaScript基础第02天 1 - 运算符(操作符) 1.1 运算符的分类 运算符(operator)也被称为操作符,是用于实现赋值.比较和执行算数运算等功能的符号. JavaScript中常用 ...

  4. 别像弱智一样提问 Stop-Ask-Questions-The-Stupid-Ways

    https://github.com/xcr1234/Stop-Ask-Questions-The-Stupid-Ways 你真的准备好了吗? 感谢群友 for you 提供 避免 xy-proble ...

  5. oracle split 以及 简单json解析存储过程

    BEGIN; 由于之前工作上需要在oracle中做split功能以及json格分解.然后经过一番google和优化整合,最后整理到一个存储过程包中,易于管理,代码如下: 1.包定义: CREATE O ...

  6. Failed to load resource: the server responded with a status of 404 ()

    今天遇到了一个一开始感觉很莫名其妙的报错 在编写页面的时候把原先写在html页面里的js代码单独拿出来做成一个JavaScriptUtil文件,放在了和html页面同一个目录下.运行之后在对应的页面c ...

  7. Dapr 远程调试之 Nocalhost

    虽然Visual studio .Visual studio code 都支持debug甚至远程debug ,Dapr 搭配Bridge to Kubernetes 支持在计算机上调试 Dapr 应用 ...

  8. UML的三项基础

    UML的定义 UML语义:描述基于UML的精确元模型定义. UML表示法:定义UML符号和文本语法提供标准. 五类模型图 用例视图:用例图 逻辑视图:类图.对象图.包图(我把包放在一起的图) 静态视图 ...

  9. python学习-Day33

    目录 今日内容详细 socket socket套接字简介 socket模块 服务端 客户端 通信循环 服务端 客户端 链接循环 半连接池 概念 产生半连接的两种情况 黏包问题 多次发送被并为一次 TC ...

  10. 排序算法详解(java代码实现)

    ​ 排序算法大致分为内部排序和外部排序两种 内部排序:待排序的记录全部放到内存中进行排序,时间复杂度也就等于比较的次数 外部排序:数据量很大,内存无法容纳,需要对外存进行访问再排序,把若干段数据一次读 ...