urlencode con solo funzioni integrate
-
19-08-2019 - |
Domanda
Senza usare plpgsql, sto cercando di urlencode un dato testo all'interno di un'istruzione SELECT pgsql.
Il problema con questo approccio:
select regexp_replace('héllo there','([^A-Za-z0-9])','%' || encode(E'\\1','hex'),'g')
... è che alla funzione di codifica non viene passato il parametro regexp, a meno che non ci sia un altro modo per chiamare le funzioni dall'espressione di sostituzione che funziona effettivamente. Quindi mi chiedo se esiste un'espressione sostitutiva che, da sola, può codificare le corrispondenze in valori esadecimali.
Potrebbero esserci altre combinazioni di funzioni. Ho pensato che ci sarebbe stata una regex intelligente (e questa potrebbe essere ancora la risposta) là fuori, ma ho difficoltà a trovarla.
Soluzione
select regexp_replace(encode('héllo there','hex'),'(..)',E'%\\1','g');
Questo non lascia i caratteri alfanumerici leggibili dall'uomo, però.
Altri suggerimenti
Ecco una funzione che ho scritto che gestisce la codifica utilizzando le funzioni integrate preservando la leggibilità dell'URL.
Regex si abbina per catturare coppie di caratteri (facoltativi) sicuri e (al massimo uno) caratteri non sicuri. Le selezioni nidificate consentono a quelle coppie di essere codificate e ricombinate restituendo una stringa completamente codificata.
Ho eseguito una suite di test con tutti i tipi di permutazioni (caratteri codificati iniziali / finali / solo / ripetuti e finora sembra codificare correttamente.
I caratteri speciali sicuri sono _ ~. - e /. La mia inclusione di " / " su quell'elenco è probabilmente non standard, ma si adatta al caso d'uso che ho dove il testo di input può essere un percorso e voglio che rimanga.
CREATE OR REPLACE FUNCTION oseberg.encode_uri(input text)
RETURNS text
LANGUAGE plpgsql
IMMUTABLE STRICT
AS $function$
DECLARE
parsed text;
safePattern text;
BEGIN
safePattern = 'a-zA-Z0-9_~/\-\.';
IF input ~ ('[^' || safePattern || ']') THEN
SELECT STRING_AGG(fragment, '')
INTO parsed
FROM (
SELECT prefix || encoded AS fragment
FROM (
SELECT COALESCE(match[1], '') AS prefix,
COALESCE('%' || encode(match[2]::bytea, 'hex'), '') AS encoded
FROM (
SELECT regexp_matches(
input,
'([' || safePattern || ']*)([^' || safePattern || '])?',
'g') AS match
) matches
) parsed
) fragments;
RETURN parsed;
ELSE
RETURN input;
END IF;
END;
$function$
Ecco una versione piuttosto breve, ed è persino " puro SQL " funzione, non plpgsql. Sono supportati caratteri multibyte (incluse emoji a 3 e 4 byte).
create or replace function urlencode(in_str text, OUT _result 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;
Puoi usare CLR e importare lo spazio dei nomi o usare la funzione mostrata in questo link, questo crea una funzione T-SQL che esegue la codifica.
http://www.sqljunkies.com /WebLog/peter_debetta/archive/2007/03/09/28987.aspx