我对 RegEx 非常缺乏经验 - 只是偶尔为我通过反复试验制定的编程任务直接使用 RegEx,但现在我遇到了一个严重的 regEx 挑战:
我有大约 970 个包含 Sybase Transact SQL 片段的文本文件,我需要在这些文件中找到每个表名并在表名前加上“#”。因此,我的选择是要么花一周时间手动编辑文件,要么使用 regEx(Python 3 或 Delphi-PRCE)编写脚本或应用程序来执行此任务。
规则如下:
表名总是大写 - 所以我只寻找大写 话;
列名、SQL 表达式和变量始终为小写;
SQL 关键字、表别名和列值可以是大写,但不能以“#”为前缀;
表别名(不能加前缀)在它们之前总是有空格,直到 前一个单词,这将是一个表名。
列值(不能有前缀)要么是数值,要么是包含在 引号。
这里是一些需要应用所有上述规则的示例文本:
update SYBASE_TABLE
set ok = convert(char(10),MB.limit)
from MOVE_BOOKS MB, PEOPLEPLACES PPL
where MB.move_num = PPL.move_num
AND PPL.mot_ind = 'B'
AND PPL.trade_type_ind = 'P'
到目前为止,我只做到了这一点:(不算太远...)
(?-i)[[:上:]]
任何帮助将不胜感激。 TIA,
锰
最佳答案
这无法通过简单的正则表达式替换来实现。您将无法区分是表格、字符串文字还是注释的大写单词:
update TABLE set x='NOT_A_TABLE' where y='NOT TABLES EITHER'
-- AND NO TABLES HERE AS WELL
编辑
您似乎认为确定一个单词是否在字符串文字中很容易,然后像这样考虑 SQL:
-- a quote: '
update TABLE set x=42 where y=666
-- another quote: '
或
update TABLE set x='not '' A '''' table' where y=666
编辑二
好吧,我(痴迷地)强调了一个简单的正则表达式替换是不可行的事实。但我还没有提供(可能的)解决方案。您可以做的是基于几个不同的正则表达式创建某种“混合词法分析器”。您要做的是扫描输入文件并在每个字符的开头尝试匹配 comment
、string literal
、keyword
,或 大写单词
。如果这 4 个先前的模式都不匹配,则只消耗一个字符并重复该过程。
Python 中的一个小演示:
#!/usr/bin/env python
import re
input = """
UPDATE SYBASE_TABLE
SET ok = convert(char(10),MB.limit) -- ignore me!
from MOVE_BOOKS MB, PEOPLEPLACES PPL
where MB.move_num = PPL.move_num
-- comment '
AND PPL.mot_ind = 'B '' X'
-- another comment '
AND PPL.trade_type_ind = 'P -- not a comment'
"""
regex = r"""(?xs) # x = enable inline comments, s = enable DOT-ALL
(--[^\r\n]*) # [1] comments
| # OR
('(?:''|[^\r\n'])*') # [2] string literal
| # OR
(\b(?:AND|UPDATE|SET)\b) # [3] keywords
| # OR
([A-Z][A-Z_]*) # [4] capitalized word
| # OR
. # [5] fall through: matches any char
"""
output = ''
for m in re.finditer(regex, input):
# append a `#` if group(4) matched
if m.group(4): output += '#'
# append the matched text (any of the groups!)
output += m.group()
# print the adjusted SQL
print output
产生:
UPDATE #SYBASE_TABLE
SET ok = convert(char(10),#MB.limit) -- ignore me!
from #MOVE_BOOKS #MB, #PEOPLEPLACES #PPL
where #MB.move_num = #PPL.move_num
-- comment '
AND #PPL.mot_ind = 'B '' X'
-- another comment '
AND #PPL.trade_type_ind = 'P -- not a comment'
这可能不是您想要的确切输出,但我希望该脚本足够简单,您可以根据自己的需要进行调整。
祝你好运。
关于regex - 使用 RegEx 解析 Transact SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6157644/