如何用Perl正则表达式替换字符串中的最后一个匹配项?

时间:2010-10-08 07:30:53

标签: regex perl

好的,这是我的测试(这不是生产代码,只是用来说明我的问题的测试)

my $string = <<EOS; # auto generated query
                SELECT
                        users.*
                        , roles.label AS role_label
                        , hr_orders.position_label
                        , deps.label AS dep_label
                        , top_deps.label AS top_dep_label
                FROM
                        users
                        LEFT JOIN $conf->{systables}->{roles} AS roles ON users.id_role = roles.id
                        LEFT JOIN (
                                SELECT
                                        id_user
                                        , MAX(dt) AS max_dt
                                FROM
                                        hr_orders
                                WHERE
                                        fake = 0
                                AND
                                        IFNULL(position_label, ' ') <> ' '
                                GROUP BY id_user
                        ) last_hr_orders ON last_hr_orders.id_user = users.id
                        LEFT JOIN hr_orders ON hr_orders.id_user = last_hr_orders.id_user AND hr_orders.dt = last_hr_orders.max_dt
                        $join
                WHERE
                        $filter
                ORDER BY
                        $order
                $limit
EOS

my $where = "WHERE\nusers.fake = -1 AND ";

$string =~  s{where}{$where}i;

print "result: \n$string";

生成查询的代码以简单的s {where} {$ where} i结尾,它取代了每次出现的地方。

我想用'WHERE users.fake = -1'替换顶级WHERE(WHERE的最后一次出现?)(实际上,模式更复杂,但没关系)。

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

为什么要通过对字符串进行硬编码然后对其进行替换来构建sql查询?不会像

那样
my $proto_query = <<'EOQ'
select ... where %s ...
EOQ

my $query = sprintf $proto_query, 'users.fake = -1 AND ...';

或(最好,因为它避免了您的初始方法和上述方法中的许多问题)使用Data::Phrasebook::SQL这样的模块可以使很多事情变得更容易?

如果你真的想进行字符串替换,你可能正在寻找像

这样的东西
my $foo = "foo bar where baz where moo";
$foo =~ s/(.*)where/$1where affe and/;
say $foo; # "foo bar where baz where affe and moo"

也就是说,尽可能多地捕捉,直到你无法捕捉到任何更多但没有“在哪里”立即跟随你捕获的内容,然后再插入你捕获的任何捕获的内容,以及你想做的任何修改。

但是,请注意,如果您使用它来破坏SQL查询,则会有各种限制。要做正确的事,你必须在某种程度上真正理解SQL。例如,考虑select ... where user.name = 'where'

答案 1 :(得分:2)

显然,我需要的是Look-ahead正则表达式功能

我的正则表达式是

s{where(?!.*where)}{$where}is;

答案 2 :(得分:2)

解析SQL查询的正确方法是使用解析器而不使用正则表达式。

参见 SQL::Statement::Structure - 解析并检查SQL查询的结构