`
duanhengbin
  • 浏览: 384840 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

用正则表达式提取SQL

阅读更多

本文记录一个用正则解决问题的过程。较多的是思路的笔记。

 

需求:   

    分析项目中 PL/SQL的表使用状况。也就是哪个程序对那些表做了增删改查。   

 

【初步分析】

    乍一看视乎不难,INSERT/UPDATE/DELETE 语句表名比较好根据位置确定,SELECT查询 FROM 关键字后面的字符串并分析,但是实际上这种方法有很大问题,首先是子查询可能出现在from节中,这种情况几乎没办法用程序分析。其次,from节的结尾判定也有很多种,不易考虑周全。

    最终确定一个可行的方案是将完整的SQL语句抽出,再利用sql语法树进行分析。 
       
【用于抽出SQL的正则表达式分析】
    DML语句都是以 SELECT/INSERT/UPDATE/DELETE 开始,以“;”结尾,但是子查询的情况比较复杂。   
    SELECT/INSERT/UPDATE/DELETE语句中都有可能出现子查询,而INSERT/UPDATE/DELETE 中有子查询可以理解为第一个出现的表名为INSERT/UPDATE/DELETE对象表,其他为 子查询对象。   
    SELECT子查询时由“(”和“)”包裹,如果抽出会造成括号不匹配,需要防止“(”后的SELECT子句被抽出 。  
    最终得到的 抽出各语句按如下正则式进行抽出。

public enum SqlDmlEnum {
	
	SELECT("(?<!\\(\\s?)select(\\s)+.*?;"),
	INSERT("(\\s)+insert(\\s)+.*?;"),
	UPDATE("(\\s)+update(\\s)+.*?;"),
	DELETE("(\\s)+delete(\\s)+.*?;");

	private final String strReg;
	private final Pattern p;

	SqlDmlEnum(String strIn) {
		this.strReg = strIn;
		this.p = Pattern.compile(strReg, Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
	}

	public List<String> extractSqls(String sqlFile) {
		Matcher m = p.matcher(sqlFile);
		List<String> list = new ArrayList<String>();
		while (m.find()) {
			list.add(m.group(0));
		}
		return list;
	}
}

注:“(?<!\\(\\s?)”左括号后面有可能有空格,本来空格数量是未定的,JAVA的逆序环视不支持不确定长度的匹配是个头痛的问题。所以简便的方法是匹配前读入阶段要将多余的空白字符删除(有多个时只留1个),就可以这样简单的匹配了。

       
【解析器选择】        
    sql的解析是最重要的一步,自己写解析树需要较多时间,还容易考虑不周。立马开始在开源项目中筛选,遗憾的是没有发现比较成熟的。最终还是选了商业化的gsp(http://www.sqlparser.com/)。作为开源控不能不说相当遗憾,今后能找到了就换。

    测试了一下功能比较强大,多重嵌套的子sql都能比较完美地解析。

    唯一发现的可能出问题的限制是 解析的SQL中的注释,需要在预处理时解决掉。   
       
【读入文本的处理(预处理)】
    这里也较多地使用了正则,首先为简化后面的处理,将回车,换行符替换为空格。

    多余的空白字符删除(有多个时只留1个)

        string.replaceAll("\\s+", " ")  
    最重要的是删除注释部分。   
    ·单行注释有两种:   
        “--”开头的字符串切除(之前前面的内容保留)

           string.replaceFirst("--.*", "")
        “REM”开头的字符串,整行忽略
    ·多行注释的删除。 如 “/*???*/”   
           string.replaceAll("/\\*(?<!\\*/).*?\\*/", "")
    ·输出消息命令 prompt,也需要删除,方法与“REM”类似。  

 

public static String readFile(String filePath) throws IOException {
	InputStream is = new FileInputStream(filePath);
	BufferedReader reader = new BufferedReader(new InputStreamReader(is));
	StringBuffer sb = new StringBuffer();
	String line = reader.readLine();
	while (line != null) {
		//注释行(以REM开头)及 输出命令(prompt)所在行跳过
		if (!(line.matches("(?i)^REM") || line.matches("(?i)^PROMPT"))){
			//单行注释删除(注意只删注释部分:"--"之后的字符串)
			//为简化后面的解析处理,将换行符转为空格
			sb.append(line.replaceFirst("--.*", "")).append(" ");
		}
		line = reader.readLine();
	}
	reader.close();
	is.close();
	//使用replaceAll("\\s+", " ") 删除多余的空格
	//使用replaceAll("/\\*(?<!\\*/).*?\\*/", "") 删除多行注释
	return sb.toString().replaceAll("\\s+", " ").replaceAll("/\\*.*?\\*/", "");
}

 

 
【其他】        
    代码中表名使用变量的部分,在excel报表中标记颜色体现。    
     个别SQL解析失败的(极少数有的话),将SQL 输出到log中。    
     IO异常不是关注重点,只做了简单抛出处理。

     使用到的第三方jar包:       
        gsp.jar    (90天免费试用期 官网http://www.sqlparser.com/  )
        log4j-1.2.17.jar   
        poi-3.7-20101029.jar   

 

【总结】

    很久没这么多使用正则了,导致初期调试费了不少周折,由于使用了多个正则表达式辅助,整个程序比较精简。JAVA的逆序环视对确定长度的限制有时比较麻烦的,如果有可能用变通的做法将目标转换为到容易确定的状态,不失为一个好的解决办法。

分享到:
评论

相关推荐

    sql_server 正则表达式

    通过CLR用户定义函数(CLR UDFs),开发者可以使用.NET Framework创建高效且健壮的函数集,大大提升了正则表达式在SQL Server中的应用效率和可维护性。 #### CLR用户定义函数详解 CLR用户定义函数实质上是在.NET程序...

    C#正则表达式提取网页数据

    本主题聚焦于利用C#的正则表达式功能来从网页中提取数据,并将其存储到SQL Server 2005数据库。下面将详细阐述这一过程中的关键知识点。 一、正则表达式(Regular Expression) 正则表达式是一种强大的文本处理工具...

    SQL 语法分析,正则表达式解析C#文件;正则表达式实现的语法分析引擎

    在这个主题中,我们将深入探讨SQL语法分析、正则表达式的应用以及如何在C#中使用正则表达式来解析文件。 首先,SQL语法分析是理解和执行SQL查询的关键步骤。当一个SQL语句被提交到数据库管理系统时,系统会对其进行...

    电话号码及日期时间提取(正则表达式 C)

    在本项目中,“电话号码及日期时间提取(正则表达式 C)”是一个使用C语言编写的程序,它能够从文本中有效地识别和提取中国大陆的手机号码和固定电话号码,以及简体中文网页中的日期和时间信息。 首先,我们要理解...

    MySQL正则表达式

    为了更好地理解如何在MySQL中使用正则表达式,下面我们通过几个具体的例子来展示其应用: 1. **查找以特定字符开头的数据** - **SQL语句**: ```sql SELECT name FROM person_tbl WHERE name REGEXP '^st'; ```...

    正则表达式在SQL Server 2000中的实现与应用.pdf

    在SQL Server 2000中,虽然标准的正则表达式支持并不内置,但开发者仍然可以通过一些方式来实现正则表达式的功能。这主要依赖于T-SQL的内置函数和一些用户定义的函数(UDF)来模拟正则表达式的行为。下面将详细介绍...

    Oracle数据库正则表达式

    使用正则表达式可以编写简洁、强大的 SQL 语句,提高数据处理的效率和灵活性。熟练使用正则表达式可以帮助用户快速搜索、替换和验证数据,并提供高度的灵活性。 在 Oracle 数据库中,正则表达式的应用非常广泛,...

    JMETER 后置处理器之正则表达式提取器(二)

    在性能测试工具 JMeter 中,后置处理器是用于在主采样器执行后处理其响应数据的组件。本文将深入探讨其中一个重要的后置处理器——正则表达式提取器...在进行复杂测试场景时,理解并熟练使用正则表达式提取器至关重要。

    Oracle正则表达式详解(用法+实例)

    这些函数的使用方式类似于传统的 SQL 函数 `LIKE`、`INSTR`、`SUBSTR` 和 `REPLACE`,但采用了 POSIX 正则表达式而不是旧式的通配符 `%` 和 `_`。 ##### 1. `REGEXP_LIKE` - **功能**: 类似于 `LIKE` 函数,用于...

    正则表达式经典实例.pdf

    例如,假设我们有一个包含日期的字符串,如`2023-04-01`,我们可以使用以下正则表达式来提取年份: ```regex (\d{4})-\d{2}-\d{2} ``` 这里,`(\d{4})`是一个捕获组,它将匹配四位数字,并将其作为一个独立的匹配...

    完全自动的正则表达式编写工具

    正则表达式是一种强大的文本处理工具,用于在字符串中匹配、查找、替换或提取特定模式。在编程和数据处理领域,正则表达式是不可或缺的一部分,但编写复杂的正则表达式往往需要深厚的知识和大量的实践。为了简化这一...

    基于Java实现正则表达式提取关键字并插入数据库

    在本项目中,我们主要探讨如何使用Java编程语言来实现正则...以上就是基于Java实现正则表达式提取关键字并插入数据库的基本流程和相关知识点。在实际开发中,可能还需要考虑错误处理、并发处理、性能优化等方面的问题。

    C++ BOOST 正则表达式使用教程

    这定义了一个正则表达式,用于匹配 SQL 语句的 select 部分。 使用 `regex_match` 函数来匹配输入字符串: ```cpp if (regex_match(in.c_str(), what, expression)) { // 匹配成功 } else { // 匹配失败 } ``` 在...

    正则表达式从入门到精通

    SQLDBA(SQL数据库管理员)在工作中也会频繁使用正则表达式,特别是在SQL查询中处理文本数据时。虽然标准SQL不直接支持正则表达式,但许多数据库系统如MySQL、PostgreSQL、Oracle和SQL Server提供了扩展函数来实现...

    协议识别的几篇好文章 IPS 正则表达式

    例如,可以创建一个正则表达式来匹配SQL注入攻击的常见字符串。当IPS检测到数据包中的内容匹配到签名时,它可以采取相应行动,如阻止数据包、记录事件或告警。 总结: 协议识别和正则表达式在网络安全中起到关键...

    利用正则表达式对SQL解释的方法

    本文将探讨如何使用正则表达式来解析SQL语句,并通过具体实例来展示这一过程。 #### 正则表达式基础 正则表达式是一种强大的文本匹配工具,可以用来查找、替换以及提取特定模式的字符串。在SQL解析场景中,通过...

    Oracle正则表达式函数全面解析

    `REGEXP_SUBSTR`函数类似于`SUBSTR`,但使用正则表达式来提取匹配项。 **语法:** ```sql REGEXP_SUBSTR(string, pattern[, position[, occurrence[, return_position]]]) ``` **示例:** 假设要提取字符串中所有...

    正则表达式AndMySQL参考文档chm

    在编程和数据分析中,正则表达式常用于数据清洗、提取关键信息和验证输入格式等任务。例如,`^[\d]{3}-[\d]{4}$` 可用于匹配美国电话号码格式。正则表达式包含多种元字符,如`.`(匹配任意字符)、`*`(重复零次或多...

Global site tag (gtag.js) - Google Analytics