Javascript encodeURI喜欢postgresql中的函数吗?

时间:2012-04-25 14:39:54

标签: postgresql stored-procedures urlencode plpgsql

PostgreSQL / plpgsql中是否有与javascripts encodeURI相同的函数/存储过程?

这是什么意思? Javascript有一个方便的内置函数来编码任何类型的URL:

encodeURI(url) - >返回已编码的URL

例如: encodeURI('http://hu.wikipedia.org/wiki/São_Paulo') - >返回一个"http://hu.wikipedia.org/wiki/S%C3%A3o_Paulo"

的字符串

我寻找完全一样的。

我不想单独编码每个参数。我不希望像javascript encodeURIComponent这样的函数不一样。上面的示例使用

生成不同的输出
encodeURIComponent('http://hu.wikipedia.org/wiki/São_Paulo')

- > "http%3A%2F%2Fhu.wikipedia.org%2Fwiki%2FS%C3%A3o_Paulo"

它对整个字符串进行编码,而不仅仅是路径部分。所以这不是我想要的。我需要一个plpgsql函数,它会产生与javascript函数encodeURI等效的输出。

谢谢!

8 个答案:

答案 0 :(得分:13)

速度慢且效率低,请考虑执行此功能的C版本:

CREATE OR REPLACE FUNCTION urlencode(in_str text, OUT _result text)
    STRICT IMMUTABLE AS $urlencode$
DECLARE
    _i      int4;
    _temp   varchar;
    _ascii  int4;
BEGIN
    _result = '';
    FOR _i IN 1 .. length(in_str) LOOP
        _temp := substr(in_str, _i, 1);
        IF _temp ~ '[0-9a-zA-Z:/@._?#-]+' THEN
            _result := _result || _temp;
        ELSE
            _ascii := ascii(_temp);
            IF _ascii > x'07ff'::int4 THEN
                RAISE EXCEPTION 'Won''t deal with 3 (or more) byte sequences.';
            END IF;
            IF _ascii <= x'07f'::int4 THEN
                _temp := '%'||to_hex(_ascii);
            ELSE
                _temp := '%'||to_hex((_ascii & x'03f'::int4)+x'80'::int4);
                _ascii := _ascii >> 6;
                _temp := '%'||to_hex((_ascii & x'01f'::int4)+x'c0'::int4)
                            ||_temp;
            END IF;
            _result := _result || upper(_temp);
        END IF;
    END LOOP;
    RETURN ;
END;
$urlencode$ LANGUAGE plpgsql;

结果:

# select urlencode('http://hu.wikipedia.org/wiki/São_Paulo');
-[ RECORD 1 ]------------------------------------------
urlencode | http://hu.wikipedia.org/wiki/S%C3%A3o_Paulo

答案 1 :(得分:6)

PL / V8 ......作弊?

create function encode_uri(text) returns text language plv8 strict immutable as $$
  return encodeURI($1);
$$;

答案 2 :(得分:4)

我编写了解决此问题的PostgreSQL扩展url_enocode

postgres=# select url_encode('http://hu.wikipedia.org/wiki/São_Paulo');
                      url_encode                       
───────────────────────────────────────────────────────
http%3A%2F%2Fhu.wikipedia.org%2Fwiki%2FS%C3%A3o_Paulo

postgres=# select uri_encode('http://hu.wikipedia.org/wiki/São_Paulo');
               uri_encode                  
---------------------------------------------
http://hu.wikipedia.org/wiki/S%C3%A3o_Paulo

答案 3 :(得分:3)

今天我遇到了&#34;赢得了3个(或更多)字节序列。&#34;对于韩国人来说,虽然我一直在使用@vyegorov的答案很长一段时间,但是一年多之后,需要更改它只需将bytea十六进制字符串转储为&#34;%&#34;前缀。

CREATE OR REPLACE FUNCTION urlencode(in_str text, OUT _result text)
    STRICT IMMUTABLE AS $urlencode$
DECLARE
    _i      int4;
    _temp   varchar;
    _hex    varchar;
    _ascii  int4;
BEGIN
    _result = '';
    FOR _i IN 1 .. length(in_str) LOOP
        _temp := substr(in_str, _i, 1);
        IF _temp ~ '[0-9a-zA-Z:/@._?#-]+' THEN
            _result := _result || _temp;
        ELSE
            _hex := encode(_temp::bytea, 'hex');
            _temp := '';
            WHILE LENGTH(_hex) > 0 LOOP
                _temp := _temp || '%' || SUBSTRING(_hex, 1, 2);
                _hex := SUBSTRING(_hex, 3, 999);
            END LOOP;
            _result := _result || upper(_temp);
        END IF;
    END LOOP;
    RETURN ;
END;
$urlencode$ LANGUAGE plpgsql;

例如,

SELECT urlencode('a') UNION ALL  --> "a"
SELECT urlencode('À') UNION ALL  --> "%C3%80"
SELECT urlencode('Ā') UNION ALL  --> "%C4%80"
SELECT urlencode('ə') UNION ALL  --> "%C9%99"
SELECT urlencode('α') UNION ALL  --> "%CE%B1"
SELECT urlencode('가') UNION ALL --> "%EA%B0%80"
SELECT urlencode('上') UNION ALL --> "%E4%B8%8A"
SELECT urlencode('い')           --> "%E3%81%84"

答案 4 :(得分:1)

这是支持多字节字符(包括3字节和4字节表情符号)的“纯SQL”(不需要plv8,plpython甚至plpgsql)实现:

create or replace function urlencode(text) returns text as $$
  select
    string_agg(
      case
        when ol>1 or ch !~ '[0-9a-zA-Z:/@._?#-]+' 
          then regexp_replace(upper(substring(ch::bytea::text, 3)), '(..)', E'%\\1', 'g')
        else ch
      end,
      ''
    )
  from (
    select ch, octet_length(ch) as ol
    from regexp_split_to_table($1, '') as ch
  ) as s;
$$ language sql immutable strict;

(来源:https://github.com/NikolayS/postgrest-google-translate/pull/8

答案 5 :(得分:1)

这是一个非常古老的线程,但是令人惊讶的是,以前发布的解决方案似乎都没有符合相关的RFC 3986。因此,这里有两个PostgreSQL函数 encode_uri (如果要编码完整的URI)和 encode_uri_component (如果要编码URI的一个组成部分,例如密钥或查询参数的值),将Nick's buggy solutionElDiabolo's noteKev's partial solution from a related thread组合成一个仅适用于SQL的有效解决方案。

工作原理:首先将字符串分解为单个字符,然后对每个多字节字符和每个不允许的字符进行十六进制编码。

编码URI组件:

create or replace function encode_uri_component(text) returns text as $$
    select string_agg(
        case
            when bytes > 1 or c !~ '[0-9a-zA-Z_.!~*''()-]+' then 
                regexp_replace(encode(convert_to(c, 'utf-8')::bytea, 'hex'), '(..)', E'%\\1', 'g')
            else 
                c
        end,
        ''
    )
    from (
        select c, octet_length(c) bytes
        from regexp_split_to_table($1, '') c
    ) q;
$$ language sql immutable strict;

编码完整的URI:

create or replace function encode_uri(text) returns text as $$
    select string_agg(
        case
            when bytes > 1 or c !~ '[0-9a-zA-Z_.!~*''();,/?:@&=+$#-]+' then 
                regexp_replace(encode(convert_to(c, 'utf-8')::bytea, 'hex'), '(..)', E'%\\1', 'g')
            else 
                c
        end,
        ''
    )
    from (
        select c, octet_length(c) bytes
        from regexp_split_to_table($1, '') c
    ) q;
$$ language sql immutable strict;

答案 6 :(得分:1)

PLPython3提供了一种直接的方法。

如果尚未安装plpython3,请安装它。命令行的示例软件包安装:

apt-get install postgresql-plpython3-9.5

创建语言(如果尚未使用其他功能)

CREATE LANGUAGE plpython3u;

此后的简单功能:

CREATE OR REPLACE FUNCTION encode_uri(input_string text)
  RETURNS text
AS $$
  import urllib.parse
  return urllib.parse.quote_plus(input_string, safe='~@#$&()*!+=:;,.?/\\''')
$$ LANGUAGE plpython3u immutable strict;

答案 7 :(得分:0)

在tsohr和Nick的答案中使用:: bytea是错误的。进行SELECT'\':: bytea看看原因。

在两种情况下,convert_to(x,'utf-8')都会产生所需的结果。

相关问题