regexp_matches postgreSQL函数中的简单参数替换

时间:2012-06-06 20:49:59

标签: sql regex postgresql plpgsql

我有一个像这样结构的表......

the_geom数据

geom1    data1+3000||data2+1000||data3+222

geom2    data1+500||data2+900||data3+22232

我想创建一个按用户请求返回记录的函数。

Example: for data2, retrieve geom1,1000 and geom2, 900

直到现在我创建了这个功能(见下文),这个功能非常好,但是我面临一个参数替换问题......(你可以看到我无法用'data2'代替$ 1 ...但是我是的以后可以使用1美元

regexp_matches(t::text, E'(data2[\+])([0-9]+)'::text)::text)[2]::integer

我的功能

create or replace function get_counts(taxa varchar(100))

returns setof record

as $$

SELECT t2.counter,t2.the_geom

FROM  (

   SELECT (regexp_matches(t.data::text, E'(data2[\+])([0-9]+)'::text)::text)[2]::integer as counter,the_geom

   from (select the_geom,data from simple_inpn2 where data ~ $1::text) as t

    ) t2

   $$
 language sql;

SELECT get_counts('data2') will work **but we should be able to make this substitution**:

regexp_matches(t::text, E'($1... instead of E'(data2....

我认为它更像是一个语法问题,因为函数执行没有错误,只需将$ 1解释为字符串并且不会产生任何结果。

提前感谢,

1 个答案:

答案 0 :(得分:1)

E'$1'是一个字符串文字(使用escape string语法),其中包含一个美元符号后跟一个。不带引号的$1是函数的第一个参数。所以这个:

regexp_matches(t, E'($1[\+])([0-9]+)'))[2]::integer
如您所见,

不会使用函数的第一个参数插入$1

正则表达式只是一个字符串,一个内部结构但仍然只是一个字符串的字符串。如果您知道$1将是一个正常的词,那么您可以说:

regexp_matches(t, E'(' || $1 || E'[\+])([0-9]+)'))[2]::integer

将字符串粘贴到合适的正则表达式中。但是,最好是有点偏执,迟早有人会用'ha ha ('之类的字符串来调用你的函数,所以你应该为此做好准备。我能想到的将一个任意字符串添加到正则表达式的最简单方法是转义所有非单词字符:

-- Don't forget to escape the escaped escapes! Hence all the backslashes.
str := regexp_replace($1, E'(\\W)', E'\\\\\\1', 'g');

然后将str粘贴到正则表达式中,如上所述:

regexp_matches(t, E'(' || str || E'[\+])([0-9]+)'))[2]::integer

或更好,在regexp_matches之外构建正则表达式以减少嵌套括号:

re := E'(' || str || E'[\+])([0-9]+)';
-- ...
select regexp_matches(t, re)[2]::integer ...

PostgreSQL没有Perl's \Q...\E(?q) metasyntax适用于正则表达式的结尾,所以我想不出更好的方法将任意字符串粘贴到正则表达式的中间作为非正则表达式的字面值比逃避一切,让PostgreSQL对其进行排序。

使用这种技术,我们可以做以下事情:

=> do $$
    declare
        m text[];
        s text;
        r text;
    begin
        s = E'''{ha)?';
        r = regexp_replace(s, E'(\\W)', E'\\\\\\1', 'g');
        r = '(ha' || r || ')';
        raise notice '%', r;
        select regexp_matches(E'ha''{ha)?', r) into m;
        raise notice '%', m[1];
    end$$;

并获得预期的

NOTICE:  ha'{ha)?

输出。但如果你遗漏了regexp_replace逃脱的步骤,你就会得到一个

invalid regular expression: parentheses () not balanced

错误。

顺便说一句,我不认为你需要所有的铸造,所以我删除它。正则表达式和转义是足够嘈杂,没有必要将一堆冒号扔进混合中。另外,我不知道你的standard_conforming_strings被设置为什么或者你正在使用哪个版本的PostgreSQL,所以我到处都有E''个字符串。您还需要将过程切换到PL / pgSQL(language plpgsql)以使转义更容易。