Вот функция, которую я написал, которая обрабатывает кодирование с использованием встроенных функций, сохраняя читаемость 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$