使用否定前瞻(或lookbehind?)从SQL中提取列名

时间:2015-12-01 05:08:51

标签: c# regex

我有一个很长的SQL脚本,我想识别SQL列名的出现,并用字典中的条目替换它们,但是我想保留参数名。

列名称的格式为schema.TableName.ColumnNameTableName.ColumnNameColumnName。参数名称的格式始终为@parameterName

所以给出了这个脚本(人为的例子):

DECLARE @foo varchar(max) = '123'
DECLARE @bar varchar(max) = '456'
SELECT foo, table.bar, @bar FROM table ORDER BY table.foo DESC

我想要匹配:

foo
table.bar
table
table.foo

我首先写了一个简单的正则表达式来匹配列名:

([A-Za-z_]+[0-9A-Za-z_]*)(\.[A-Za-z_]+[0-9A-Za-z_])*(\.[A-Za-z_]+[0-9A-Za-z_])*

(这是一个从左到右构建的黑客,所以第一个匹配的组是列名(如果是单标记的),表名(如果是双重标记的),或者模式名称(如果是完全限定的),但这不是一个大问题。)

...除了这个正则表达式之外还在at符号后面立即选择参数部分。所以我需要修改它,使其与参数不匹配。我添加了一个负面后瞻断言(?<!\@)以匹配前导@前缀,然后取消匹配,但它不起作用:

((?<!\@)([A-Za-z_]+[0-9A-Za-z_]*)(\.[A-Za-z_]+[0-9A-Za-z_])*(\.[A-Za-z_]+[0-9A-Za-z_])*

尽管存在负面观察断言,但鉴于输入“@foobar”,它匹配/捕获“@f[oobar]”而不是拒绝捕获它。

显然我没有正确使用lookbehind断言。我已经尝试将断言置于父组内外,并尝试使用否定前瞻断言,但没有效果。

1 个答案:

答案 0 :(得分:1)

至于修复你的表达方式,你错过了一个\ b来表明我们在这个单词的开头。

(?<!@)\b([A-Za-z_]+\w*)(\.[A-Za-z_]+\w*)*\b

那将匹配

'SELECT', 'foo', 'table.bar', 'FROM', 'table', 'ORDER', 'BY', 'table.foo', 'DESC'

来自声明

SELECT foo, table.bar, @bar FROM table ORDER BY table.foo DESC

我觉得单凭正则表达式可能不是最佳解决方案 最好尝试找一个sql解析器或编写一个简单的解析器,在遇到列名时替换它们。