String 用二进制字符串替换子字符串
我想对二进制字符串执行子字符串替换操作。有一个函数可以对String 用二进制字符串替换子字符串,string,postgresql,replace,binary,postgresql-9.2,String,Postgresql,Replace,Binary,Postgresql 9.2,我想对二进制字符串执行子字符串替换操作。有一个函数可以对text()类型的字符串执行此操作: 但不幸的是,bytea()类型的二进制字符串没有 现在我想知道,我是否需要为二进制字符串重新实现此操作,或者我是否可以使用相应的基本字符串函数来完成此任务?是否存在可能破坏我的应用程序的边缘案例: select replace('\000\015Hello World\000\015Hello World'::bytea::text, 'World',
text
()类型的字符串执行此操作:
但不幸的是,bytea
()类型的二进制字符串没有
现在我想知道,我是否需要为二进制字符串重新实现此操作,或者我是否可以使用相应的基本字符串函数来完成此任务?是否存在可能破坏我的应用程序的边缘案例:
select replace('\000\015Hello World\000\015Hello World'::bytea::text,
'World',
'Jenny')::bytea
到目前为止,我在文档中找不到具体的注释。有人能帮我一下吗?转换到
文本
并返回到bytea
的问题是,如果替换字符串涉及字符串中带引号的字节,它将无法工作。让我们看一个例子
(我正在将bytea\u output
设置为hex
以更好地查看文本,否则都是十六进制数)
初始查询:
with input(x) as (values (('\000\015Hello World\000\015Hello World'::bytea)))
select replace(x::text, 'World', 'Jenny')::bytea from input;
结果很好:
replace
----------------------------------------
\000\015Hello Jenny\000\015Hello Jenny
(1 row)
结果是:
replace
----------------------------------------
IMHello 1orldIMHello 1orld
代替
----------------------------------------
IMHello 1orldIMHello 1orld
而期望的结果是:\000\015你好1orld\000\015你好1orld
。
这是因为中间表示法
\000\015
被替换为\111\115
转换为文本并返回到bytea
的问题是,如果替换字符串涉及字符串中带引号的字节,则无法工作。让我们看一个例子
(我正在将bytea\u output
设置为hex
以更好地查看文本,否则都是十六进制数)
初始查询:
with input(x) as (values (('\000\015Hello World\000\015Hello World'::bytea)))
select replace(x::text, 'World', 'Jenny')::bytea from input;
结果很好:
replace
----------------------------------------
\000\015Hello Jenny\000\015Hello Jenny
(1 row)
结果是:
replace
----------------------------------------
IMHello 1orldIMHello 1orld
代替
----------------------------------------
IMHello 1orldIMHello 1orld
而期望的结果是:\000\015你好1orld\000\015你好1orld
。
这是因为中间表示法\000\015
被替换为\111\115
根据@DanielVériteé的建议,我实现了一个plpgsql
函数,该函数将字符串替换为bytea
类型的二进制字符串。
在实现中,我只使用了二进制字符串部分的函数,因此我认为应该可以安全使用
这是我的密码:
CREATE OR REPLACE FUNCTION
replace_binary(input_str bytea, pattern bytea, replacement bytea)
RETURNS bytea
AS $$
DECLARE
buf bytea;
pos integer;
BEGIN
buf := '';
-- validate input
IF coalesce(length(input_str), 0) = 0 OR coalesce(length(pattern), 0) = 0
THEN
RETURN input_str;
END IF;
replacement := coalesce(replacement, '');
LOOP
-- find position of pattern in input
pos := position(pattern in input_str);
IF pos = 0 THEN
-- not found: append remaining input to buffer and return
buf := buf || substring(input_str from 1);
RETURN buf;
ELSE
-- found: append substring before pattern to buffer
buf := buf || substring(input_str from 1 for pos - 1);
-- append replacement
buf := buf || replacement;
-- go on with substring of input
input_str := substring(input_str from pos + length(pattern));
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql
IMMUTABLE;
至于我的测试用例,它工作得相当好:
with input(buf, pattern, replacement) as (values
('tt'::bytea, 't'::bytea, 'ttt'::bytea),
('test'::bytea, 't'::bytea, 'ttt'::bytea),
('abcdefg'::bytea, 't'::bytea, 'ttt'::bytea),
('\000\015Hello 0orld\000\015Hello 0orld'::bytea, '0'::bytea, '1'::bytea))
select encode(replace_binary(buf, pattern, replacement), 'escape') from input;
预期产出:
encode
------------------------------------
tttttt
tttesttt
abcdefg
\000\rHello 1orld\000\rHello 1orld
(4 rows)
根据@DanielVérité的建议,我实现了一个plpgsql
函数,该函数用类型为bytea
的二进制字符串替换字符串。
在实现中,我只使用了二进制字符串部分的函数,因此我认为应该可以安全使用
这是我的密码:
CREATE OR REPLACE FUNCTION
replace_binary(input_str bytea, pattern bytea, replacement bytea)
RETURNS bytea
AS $$
DECLARE
buf bytea;
pos integer;
BEGIN
buf := '';
-- validate input
IF coalesce(length(input_str), 0) = 0 OR coalesce(length(pattern), 0) = 0
THEN
RETURN input_str;
END IF;
replacement := coalesce(replacement, '');
LOOP
-- find position of pattern in input
pos := position(pattern in input_str);
IF pos = 0 THEN
-- not found: append remaining input to buffer and return
buf := buf || substring(input_str from 1);
RETURN buf;
ELSE
-- found: append substring before pattern to buffer
buf := buf || substring(input_str from 1 for pos - 1);
-- append replacement
buf := buf || replacement;
-- go on with substring of input
input_str := substring(input_str from pos + length(pattern));
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql
IMMUTABLE;
至于我的测试用例,它工作得相当好:
with input(buf, pattern, replacement) as (values
('tt'::bytea, 't'::bytea, 'ttt'::bytea),
('test'::bytea, 't'::bytea, 'ttt'::bytea),
('abcdefg'::bytea, 't'::bytea, 'ttt'::bytea),
('\000\015Hello 0orld\000\015Hello 0orld'::bytea, '0'::bytea, '1'::bytea))
select encode(replace_binary(buf, pattern, replacement), 'escape') from input;
预期产出:
encode
------------------------------------
tttttt
tttesttt
abcdefg
\000\rHello 1orld\000\rHello 1orld
(4 rows)
你的postgresql版本是什么?您提供的混合9.2和8.0文档页面的链接,以及字符串中反斜杠的解释也取决于版本。@DanielVérité它的版本是9.2。您的postgresql版本是什么?您提供的混合9.2和8.0文档页面的链接,以及字符串中反斜杠的解释也取决于版本。@DanielVéritéit的版本9.2我不知道。我认为::text
-表示法会将不可打印的字节保留为单个字节,但实际上,八位字节长度(x)
并不等于八位字节长度(x::text)
。是否存在/你知道一个变通方法?我看不到一个简单的变通方法。我想我应该在plpgsql
中迭代执行,而不强制转换为文本,并使用position
在循环中定位和overlay
替换。我不知道这一点。我认为::text
-表示法会将不可打印的字节保留为单个字节,但实际上,八位字节长度(x)
并不等于八位字节长度(x::text)
。是否存在/你知道一个变通方法?我看不到一个简单的变通方法。我想我应该在plpgsql
中迭代执行,而不强制转换为文本,并使用position
在循环中定位和overlay
替换。