正则表达式替换匹配后的所有匹配项

时间:2017-01-21 13:56:16

标签: 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)

我尝试过lookbehind或简单的https://regex101.com/r/sfhDpt/1,但它只匹配一个实例。

上下文是SQL转换 - 原始SQL在MSSQL或Oracle中工作但在DB2或H2中不起作用所以我需要一种简单的方法(读取,正则表达式)来在需要时进行转换。

这可以用一个正则表达式完成吗?

4 个答案:

答案 0 :(得分:1)

这样的正则表达式应该这样做(<table> <colgroup> <col class="highlight"> <col> </colgroup> <thead> <tr> <th colspan="2">1</th> </tr> </thead> <tbody> <tr> <td>1.1</td> <td>1.2</td> </tr> </tbody> </table> <br> <table> <colgroup> <col> <col class="highlight"> </colgroup> <thead> <tr> <th colspan="2">1</th> </tr> </thead> <tbody> <tr> <td>1.1</td> <td>1.2</td> </tr> </tbody> </table>语法):

perl

它利用了第三组的重复匹配。 test

编辑:不幸的是,上述内容不适用于超过2个s/(order by)((.*?)upper)*/$1$3/s 字符串,因为重复匹配组仅捕获最后一次出现。要在upper中捕获所有这些,可以写一下:

perl

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

当然,重复也可以手动展开:

callouts

但在这种情况下s/(order by)((.*?)upper)?((.*?)upper)?((.*?)upper)?((.*?)upper)?/$1$3$5$7$9/s 必须重复(连同替换变量),因为((.*?)upper)?可能会在源字符串中重复多次。 test

答案 1 :(得分:1)

这适用于upper(...)中最多3次order by次来电:

(order by (?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)(?:upper(\(.*?\)))?((?:(?!upper).)*)

将匹配替换为:

$1$2$3$4$5$6$7

它也不会出现upper()

如果您发现需要更多捕获,请重复最后一对捕获组,然后再添加两个反向引用。

请参阅live demo

答案 2 :(得分:0)

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

这是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";

<强>输出:

select upper(a.col1), b.col1
from a join
     b
     on a.q = b.q
order by  (a.col1),  (b.col1)

答案 3 :(得分:0)

确定。根据您对上述查询的回复,我就是这样解释问题:

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

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

因此,您希望使用正则表达式来删除查询中有问题的部分 - 这是在两个不起作用的目标数据库的order-by子句中。

方法1:

首先,我认为更好的解决方法是简单地让应用程序知道数据库集并让它发送查询标识符,然后为特定数据库定制查询。

这种方法还将确保所产生的功能损失 - 由大写字母排序的结果可以在应用程序层中处理,因为它使用不支持它的数据库。

最好使用prepared-statements(如果应用程序使用的语言支持它,或者你可以构建一个专门用于数据库访问的层,这显然是你正在做的 - 因为你似乎有一个点你要拦截传入的查询)。

使用prepared-statement有助于sql-injection和查询优化。

方法2:

如果上述内容严格不可行且您仍想使用reg-exp,则可以将查询分为两部分: a)在订购之前和之后 b)订购后 并替换所有出现的&#39; upper&#39;在order-by之后的部分中使用空字符串。

然后,您可以在排序前(和包括)顺序连接第一部分,最后一部分连接&#39; upper&#39;已替换关键字以获取所需的查询。

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