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等效的输出。
谢谢!
答案 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 solution,ElDiabolo's note和Kev'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')都会产生所需的结果。