urlencode только со встроенными функциями

Без использования plpgsql я пытаюсь urlencode данного текста в операторе pgsql SELECT.

Проблема с этим подходом:

select regexp_replace('héllo there','([^A-Za-z0-9])','%' || encode(E'\\1','hex'),'g')

... заключается в том, что функции кодирования не передается параметр регулярного выражения, если нет другого способа вызова функций из выражения замены, которое действительно работает. Поэтому мне интересно, есть ли заменяющее выражение, которое само по себе может кодировать совпадения в шестнадцатеричные значения.

Возможны и другие комбинации функций. Я думал, что там будет умное регулярное выражение (и это все еще может быть ответом), но у меня возникли проблемы с его поиском.


person Kev    schedule 04.12.2008    source источник


Ответы (4)


select regexp_replace(encode('héllo there','hex'),'(..)',E'%\\1','g');

Однако это не делает буквенно-цифровые символы удобочитаемыми для человека.

person Kev    schedule 04.12.2008

Вот функция, которую я написал, которая обрабатывает кодирование с использованием встроенных функций, сохраняя при этом удобочитаемость URL-адреса.

Сопоставления регулярных выражений для захвата пар (необязательных) безопасных символов и (не более одного) небезопасного символа. Вложенные выборки позволяют кодировать и повторно комбинировать эти пары, возвращая полностью закодированную строку.

Я прошел набор тестов со всеми видами перестановок (начальные/конечные/только/повторяющиеся закодированные символы, и до сих пор он, кажется, правильно кодирует.

Безопасными специальными символами являются _ ~ . - а также /. Мое включение «/» в этот список, вероятно, нестандартно, но подходит для моего варианта использования, когда входной текст может быть путем, и я хочу, чтобы он остался.

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$
person Paul Christmann    schedule 09.11.2015
comment
Спасибо за все время, которое вы потратили на это, но, как указано в OP, я искал чистые встроенные функции без pl/pgsql. - person Kev; 10.11.2015

Вот довольно короткая версия, и это даже функция "чистого SQL", а не plpgsql. Поддерживаются многобайтовые символы (включая 3- и 4-байтовые эмодзи).

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;
person Nick    schedule 19.10.2016
comment
Обратите внимание, что ch::bytea::text зависит от того, ch может анализироваться как литерал BYTEA. Кажется, это работает для всего, кроме ``. - person djmitche; 18.04.2020

Вы можете использовать CLR и импортировать пространство имен или использовать функцию, показанную в этой ссылке, это создает функцию T-SQL, которая выполняет кодирование.

http://www.sqljunkies.com/WebLog/peter_debetta/archive/2007/03/09/28987.aspx

person Coolcoder    schedule 08.12.2008
comment
Кроме того, я пытаюсь использовать только встроенные функции, т. е. не хочу создавать функцию или хранимую процедуру. - person Kev; 05.01.2009