Java 正则表达式替换匹配后的所有引用

Java 正则表达式替换匹配后的所有引用,java,regex,Java,Regex,我希望删除以下语句中ORDER BY之后的upper关键字: select upper(a.col1), b.col1 from a join b on a.q = b.q order by upper(a.col1), upper(b.col1) 期望输出: select upper(a.col1), b.col1 from a join b on a.q = b.q order by (a.col1), (b.col1) 我尝试过lookbehin

我希望删除以下语句中ORDER BY之后的upper关键字:

select upper(a.col1), b.col1
from a join
     b
     on a.q = b.q
order by upper(a.col1), upper(b.col1)
期望输出:

select upper(a.col1), b.col1
from a join
     b
     on a.q = b.q
order by (a.col1), (b.col1)
我尝试过lookbehind或simple,但它只匹配一个实例

上下文是SQL翻译-原始SQL在MSSQL或Oracle中工作,但在DB2或H2中不工作,因此我需要一种简单的方法(read,regex)在需要时进行转换


这甚至可以用一个正则表达式来实现吗?

这样的正则表达式应该做到这一点(
perl
语法):

它利用了第三组重复匹配的优势

编辑:不幸的是,上面的内容不适用于2个以上的
字符串,因为重复匹配组只捕获最后一次出现的内容。要在
perl
中捕获所有这些代码,可以编写:

s/(order by)(?{$x=""})((.*?)(?{$x.=$3})upper)*/$1$x/s
它捕获$x变量中所有$3的出现。这在regexp中使用
perl
代码执行,在
pcre
中不起作用(尽管
callout
可以在那里调用外部函数来执行类似的操作)

当然,重复也可以手动展开,如下所示:

s/(order by)((.*?)upper)?((.*?)upper)?((.*?)upper)?((.*?)upper)?/$1$3$5$7$9/s

但是在这种情况下,
(.*upper)?
必须重复(连同替换变量),重复次数与源字符串中的
upper
相同

只有一个正则表达式似乎很难


以下是php的解决方案:

$sql = <<<EOD
select upper(a.col1), b.col1
from a join
     b
     on a.q = b.q
order by upper(a.col1), upper(b.col1)
EOD;

$sql = preg_replace_callback('/(?=order by )(.*$)/', 
        function ($m) {
            return preg_replace('/\bupper\b/', ' ', $m[1]);
        },
        $sql
       ); 
echo $sql,"\n";

这将适用于按
顺序进行的最多3个
上限(…)
调用:

(order by (?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)
将匹配项替换为:

$1$2$3$4$5$6$7
它也适用于不出现
upper()
的情况

如果您发现需要更多捕获,请重复最后一对捕获组,并向替换添加两个以上的反向引用


请参阅。

确定。根据您对我上述问题的答复,我对问题的解释如下:

有一个具有相当标准语法的SQL查询,因此理想情况下,它应该运行在任何数据库中,特别是mssql、oracle、db2和h2

但是,在这种特殊情况下,查询具有某些语法,在mssql和oracle中运行正常,但在db2和h2中运行不正常

因此,您需要一个正则表达式来删除查询中有问题的部分,该部分在两个目标数据库的order by子句中,在这两个数据库中,正则表达式不起作用

方法1:

第一点是,我认为解决这个问题的更好方法是让应用程序知道数据库集,让它发送一个查询标识符,然后根据特定的数据库定制查询

这种方法还将确保所导致的功能损失(按大写字母排序的结果)可以在应用程序层中处理,因为它使用的是不支持它的数据库

最好使用预先准备好的语句(如果应用程序使用的语言支持它,或者如果您可以构建一个专门用于数据库访问的层,这显然是您正在做的——因为您似乎有一个截取传入查询的点)

使用prepared语句有助于sql注入和查询优化

方法2:

如果上述方法严格来说是不可行的,并且您仍然希望使用reg exp,那么您可以将查询分为两个部分: a) 在订购之前,包括 b) 订购后 并在order by之后的节中将所有出现的“upper”替换为空字符串

然后,您可以将order by之前(包括)的第一个部分与替换了“upper”关键字的最后一个部分连接起来,以返回所需的查询


您还可以尝试反转查询,然后搜索第一个出现的
yb[\s]+redro
,获取索引,提取子字符串,并将所有出现的
)[\s]+reppu
替换为
,然后将字符串反转回来并再次连接。

仅供我理解,为什么只在order by子句中删除upper函数的用法?这两个查询都应该在任何数据库中工作。您确定查询中没有分组依据吗?或者,也许样本数据和期望的结果可以更好地解释您真正想要做的事情。按的顺序使用
upper()
的次数是否合理?如果是这样,那么限制是什么?@RavindraHV-正如我提到的,如果上限(或其他标量函数)不是选择的一部分,DB2和H2不允许使用上限(或其他标量函数)。在我的例子中,b.col1就是问题所在。我知道SQL的格式不正确,但应用程序就是这样编写的。@Bohemian-我已经追踪到旧版应用程序Nice one传递的SQL中最多出现3次,但它在order by子句中的列数不超过2列。@mik-我无法使它工作。您可以将您的正则表达式保存在regex101.com或其他在线正则表达式测试器上吗?Thanks@Yan我刚刚添加了测试链接,非常聪明@mik!但是我使用的是Java,因此带有嵌入式perl的正则表达式无法工作。@Yan Java也不支持调用,因此您需要坚持重复该模式
(order by (?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)
$1$2$3$4$5$6$7