Unescape带有转义换行符和回车符的字符串

时间:2016-01-19 02:36:46

标签: sql database postgresql special-characters plpgsql

我正在尝试编写一个混淆/审查/编辑文本的PLPGSQL函数。

-- Obfuscate a body of text by replacing lowercase letters and numbers with # symbols.
CREATE OR REPLACE FUNCTION obfuscate(str text) RETURNS text AS $$
BEGIN
  str := replace(str, '\r', E'\r');
  str := replace(str, '\n', E'\n');
  str := translate(str, 'abcdefghijklmnopqrstuvwxyz0123456789', rpad('#',36,'#'));
  str := replace(str, E'\r', '\r');
  str := replace(str, E'\n', '\n');
  RETURN str;
END
$$ LANGUAGE plpgsql;

这样可行,但请注意舞蹈将转义的换行符和回车符转换为各自的字节,然后再返回。这是因为我的数据集包含已被转义的字符串(已被序列化为JSON / YAML的数据),我不想破坏这些值。

还有另一种更方便的方法来取消字符串吗?处理其他转义值也很棒,比如unicode转义序列。

1 个答案:

答案 0 :(得分:2)

To" unescape"一个字符串,你必须"执行"它 - 字面意思。使用EXECUTE command in plpgsql
您可以将其包装成一个函数。天真的方法:

CREATE OR REPLACE FUNCTION f_unescape(text, OUT _t text) AS
$func$
BEGIN
   EXECUTE 'SELECT E''' || $1 || ''''
   INTO _t;
END
$func$  LANGUAGE plpgsql STABLE;

呼叫:

SELECT f_unescape('\r\nabcdef\t0123\x123\n');

这种天真的形式容易受到原始字符串中的单引号的影响,需要对其进行转义。但这有点棘手。单引号可以使用posix转义字符串语法以两种方式转义:\'''。但我们也可能有\\'等基础知识:

我们可以将字符串括在美元引用中,但这不适用于posix转义字符串语法。 E'\''无法替换为 E$$\'$$ 。我们可以在函数中添加SET standard_conforming_strings = off,然后我们就不必在E前添加字符串了。但这会禁用函数体内的函数内联和解释转义。

相反,使用'转义所有\和所有(可选)前导regexp_replace()

regexp_replace($1, '(\\*)(\''+)', '\1\1\2\2', 'g')

(\\*) .. 0或更多领先\
 (\''+) ..捕获1个或多个'
 '\1\1\2\2' ..每场比赛加倍  'g' ..替换所有匹配项,而不仅仅是第一个

安全功能

CREATE OR REPLACE FUNCTION f_unescape(IN text, OUT _t text)
  RETURNS text AS
$BODY$
BEGIN
   EXECUTE $$SELECT E'$$ || regexp_replace($1, '(\\*)(\''+)', '\1\1\2\2', 'g') || $$'$$
   INTO _t;
END
$BODY$
  LANGUAGE plpgsql STABLE;

我假设你知道操作无法逆转可靠。没有办法告诉哪个特殊字符之前已被转义,哪个不是。你可以逃脱全部或全部。或者像以前一样手动完成。但如果文字和转义形式中包含相同的字符,则不能再将它们分开。

测试用例:

SELECT t, f_unescape(t)
FROM  (
   VALUES
     ($$'$$)
   , ($$''$$)
   , ($$'''$$)
   , ($$\'$$)
   , ($$\\'$$)
   , ($$\\\'$$)
   , ($$\\\'''$$)
   , ($$\r\\'nabcdef\\\t0123\x123\\\\\'''\n$$)
   ) v(t);