scala使用正则表达式来提取sql语句中的fields子句
我想开发一个简单的函数来替换sql语句中的fields子句 像这样的scala使用正则表达式来提取sql语句中的fields子句,sql,regex,Sql,Regex,我想开发一个简单的函数来替换sql语句中的fields子句 像这样的 replaceFields("select * from x", "f1") // should return "select f1 from x" replaceFields("select top 10 * FROM x", "f1") // should return "select top 10 f1 FROM x" replaceFields("select top 10 f3, f4 FROM
replaceFields("select * from x", "f1")
// should return "select f1 from x"
replaceFields("select top 10 * FROM x", "f1")
// should return "select top 10 f1 FROM x"
replaceFields("select top 10 f3, f4 FROM x", "f1, f2")
// should return "select top 10 f1, f2 FROM x"
我知道这应该很简单,但我尝试了一些正则表达式,但似乎找不到
"select * from".replaceFirst("""select (\w+) from""", "count(*)")
// returns "select * from"
"select * from".replaceFirst("""select(\b(.*))\bfrom""", "count(*)")
// returns "count(*)"
但它不起作用…您正在正确地更换
select(\b(.*))\bfrom
如果只想替换选择
和from
之间的部分,则不应将这些部分包含在要替换的字符串中。试一试
(?<=select\b)(.*?) from
编辑:
似乎要替换表中的列列表
假设每个列名都位于select语句后面的关键字列表(如TOP
)之后,我创建了这个正则表达式,其中包含相关参数
(([^\s]+,\s+)*([^\s]+)\s+)from
它基于这样一个原则:列名(您要替换的列名)要么是来自的前面的标记(请允许我用这个词),要么是用逗号将其与其他标记分开
然后以这种方式处理该案件
token token, token FROM
^this is the starting point of substitution
token FROM
^this is the starting point
用你想要的替换第一组,你就没事了。测试它多亏了gabber的帮助,以及(并非如此)对正则表达式的一点点挣扎,我找到了这个解决方案:
def replaceFields(sql: String, fields: String): String = {
val parseSql = """(?imx) #insensitive case, multiline, whitespaces and comments
(^ select \s+ #(?:top \s+ \d+ \s+)?) #m1: select clause and optional clauses
(?:top \s+ \d+ \s+)? # top x clause (ignored match)
(?:(?:distinct|all) \s+)? # distinct | all clause (ignored match)
)
(.+?) #m2: the field clause I'm looking for, non greedy to leave spaces to match3
(\s+ from \s+ .* $) #m3: the rest of the sql sentence, greedy spaces
""".r
val replace = "$1%s$3".format(fields) // replace match2 with new fields
parseSql.replaceFirstIn(sql, replace)
}
其中:
scala> replaceFields("select * from x", "count(*)")
res1: String = select count(*) from x
scala> replaceFields("select top 24 f1, f2 from x", "f3, f4, f5")
res2: String = select top 24 f3, f4, f5 from x
scala> replaceFields("select f1 from x", " f2, f3 ")
res3: String = select f2, f3 from x
scala> replaceFields("select top 23 distinct f1, f2 from x", "f3, f4, f5")
res0: String = select top 23 distinct f3, f4, f5 from x
“没用”。。。发生了什么事?我在每行后面添加了表达式返回的内容作为注释。。。将为clarityAh编辑它,对吧对不起,我看到了第一个列表,但忽略了第二个列表。这里是它不起作用的原因:第一个没有找到*
,因为\w
将只匹配[a-zA-Z0-9]
。第二个不匹配,但完全匹配表示整个字符串,因此替换整个字符串。我不知道这在您的环境中是如何工作的,但是您需要替换第一个捕获组。另外,您的第二个模式将包括捕获中的空格。您的预期结果从x中选择前10个计数(*)无效。这只是一个示例,可能有任何字段列表,我将对其进行编辑以获得清晰的答案非常有用,问题是在fields子句中可能有一些奇怪的内容,如“select Upper”表1中的(f1)、f2*2等”是的,我认为这不可能适用于所有情况。我认为最好的解决方案是设置一组关键字,可以在select语句之后找到,并将它们放在正则表达式中的
列表中,就像您对top
所做的那样,但使用其他代码段,如DISTINCT
添加了DISTINCT和all支持:)你找到答案后,最多只能给你+1个奖励!小心,如果您编写(\s+from\s+
),则在from前面需要两个空格,后面需要三个空格\s+
表示1+个空格,然后在\s+
和中的之间添加一个空格。同样的事情在(?imx)开始时,“x”告诉scala忽略这些空白,所以这与写入(\s+来自\s+.*$)是一样的,我认为我的版本更具可读性……事实上,我只是不知道这个特性:)
scala> replaceFields("select * from x", "count(*)")
res1: String = select count(*) from x
scala> replaceFields("select top 24 f1, f2 from x", "f3, f4, f5")
res2: String = select top 24 f3, f4, f5 from x
scala> replaceFields("select f1 from x", " f2, f3 ")
res3: String = select f2, f3 from x
scala> replaceFields("select top 23 distinct f1, f2 from x", "f3, f4, f5")
res0: String = select top 23 distinct f3, f4, f5 from x