使用转义换行符和回车符对字符串进行转义

Posted

技术标签:

【中文标题】使用转义换行符和回车符对字符串进行转义【英文标题】:Unescape a string with escaped newlines and carriage returns 【发布时间】:2016-01-19 02:36:46 【问题描述】:

我正在尝试编写一个混淆/审查/编辑文本的 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】:

要“取消转义”字符串,您必须“执行”它 - 字面意思。使用EXECUTE command in plpgsql。 您可以将其包装成一个函数。幼稚的做法:

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

呼叫:

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

这个简单的函数容易受到原始字符串中的单引号的影响,需要对其进行转义。但这有点棘手。在 Posix 转义字符串语法中,单引号可以通过两种方式转义:\'''。但我们也可以有\\' 等。基础知识:

Insert text with single quotes in PostgreSQL

我们可以将字符串括在美元引号中,但这不适用于 Posix 转义字符串语法。 E'\'' 不能替换为 E$$\'$$。我们可以将SET standard_conforming_strings = off 添加到函数中,然后我们就不必在字符串前面加上E。但这会禁用函数内联,并且 interpret 在函数体的任何地方都会转义。

相反,转义所有' 和所有(可选)前导\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
  LANGUAGE plpgsql STABLE AS
$func$
BEGIN
   EXECUTE $$SELECT E'$$ || regexp_replace($1, '(\\*)(\''+)', '\1\1\2\2', 'g') || $$'$$
   INTO _t;
END
$func$;

操作无法逆转可靠。没有办法知道哪个特殊字符之前被转义了,哪个没有。您可以全部逃避,也可以不逃避。或者像以前一样手动进行。但如果文字和转义形式中包含相同的字符,则无法再区分它们。

测试用例:

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

【讨论】:

以上是关于使用转义换行符和回车符对字符串进行转义的主要内容,如果未能解决你的问题,请参考以下文章

Java转义字符, 注释

Java转义字符和进制的转换

转义序列各字符间可以有空格吗 是回车换刚么

转义字符

java的转义字符

转义字符