2012-04-25 4 views
5

Esiste qualche funzione/stored procedure in PostgreSQL/plpgsql che è uguale a javascripts encodeURI?Funzione encode di codifica JavaScript in Postgresql?

Che cosa significa? Javascript hanno un pratico costruito in funzione per codificare qualsiasi tipo di url:

encodeURI (url) -> restituisce l'URL codificato

Ad esempio: encodeURI('http://hu.wikipedia.org/wiki/São_Paulo') -> restituisce una stringa che è "http://hu.wikipedia.org/wiki/S%C3%A3o_Paulo"

I cercando esattamente la stessa cosa.

Non voglio codificare ciascun parametro separatamente. Non voglio una funzione come javascript encodeURIComponent che non è la stessa cosa. L'esempio precedente risulta un output diverso con

encodeURIComponent('http://hu.wikipedia.org/wiki/São_Paulo') 

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

È codificare l'intera stringa non solo la parte percorso. Quindi questo non è quello che sto cercando. Ho bisogno di una funzione plpgsql che restituisca un output equivalente alla funzione javascript encodeURI.

Grazie!

risposta

4

ho scritto estensioni PostgreSQL url_enocode che risolvono questo problema

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 

o

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

Questa sembra la soluzione più vicina di cui ho bisogno ... – Roki

+0

Forse lo modifico un po '... Ha un bug, dopo il protocollo (http) ... Se aggiungi c ==': 'sulla 95esima riga, funzionerà perfettamente ... (e anche la linea 154 ... per essere coerente) – Roki

+0

Questa è solo la versione iniziale - Aggiungerò una funzione uri_encode e uri_decode, non posso modificare come si propone, perché: sono caratteri riservati. –

11

lento e inefficiente, in considerazione di fare C versione di questa funzione:

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; 

Risultati:

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

Oh, grazie! Sto cercando una funzione incorporata o una libreria postgres da installare che contenga questo tipo di funzione. Sono ottimista, penso che qualcuno l'abbia fatto prima di noi, perché è un problema semplice/quotidiano ... Ho fatto anche la stessa procedura memorizzata, ma come hai scritto tu, è inefficiente e lento. E sì, come hai detto che la versione C nativa è l'unico modo per farlo urlare ...Quindi, la mia domanda riguarda cosa installare, cosa usare, che è la migliore libreria per questo, non scrivere un tipo di codice ... :-) – Roki

6

Con PL/V8 ... imbrogliare?

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

Ecco "puro SQL" (senza plv8, plpython o anche plpgsql necessario) attuazione supporto caratteri multibyte (incluso emoji 3 e 4 byte):

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; 

(fonte: https://github.com/NikolayS/postgrest-google-translate/pull/8)

1

Oggi ho riscontrato "Non si occuperanno di 3 (o più) sequenze di byte". per i personaggi coreani mentre utilizzo la risposta di @vyegorov da parecchio tempo, più di un anno, ho bisogno di cambiarlo semplicemente buttando le stringhe esadecimali con "%" prefissato.

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; 

esempio,

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" 
+0

Anch'io ... Grazie. – sashaegorov