Как я могу заменить только последнее вхождение в строке с регулярным выражением Perl? - PullRequest
3 голосов
/ 08 октября 2010

Хорошо, вот мой тест (это не рабочий код, а всего лишь тест, иллюстрирующий мою проблему)

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.

Я хочу заменить верхний уровень WHERE (последнее появление WHERE?) На «WHERE users.fake = -1» (на самом деле, на более сложный шаблон, но это не имеет значения).

Есть идеи?

Ответы [ 3 ]

3 голосов
/ 08 октября 2010

Почему вы хотите создавать свои 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'.

2 голосов
/ 08 октября 2010

Правильный способ разбора SQL-запросов - это сделать это с помощью синтаксического анализатора и без использования регулярных выражений.

see SQL :: Statement :: Structure - parseи изучить структуру SQL-запросов

2 голосов
/ 08 октября 2010

очевидно, что мне нужно было Предварительный просмотр функция регулярного выражения

мое регулярное выражение

s{where(?!.*where)}{$where}is;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...