2

我想对二进制字符串执行子字符串替换操作。有一个可用的函数可以对类型textcf)的字符串执行此操作:

replace(string text, from text, to text)

但不幸的是,对于类型byteacf)的二进制字符串没有。

现在我想知道,我是否需要为二进制字符串重新实现这个操作,或者我可以使用相应的基本字符串函数来完成这个任务?是否有可能破坏我的应用程序的边缘情况:

select replace('\000\015Hello World\000\015Hello World'::bytea::text,
               'World',
               'Jenny')::bytea

到目前为止,我在文档中找不到特定的注释。有人可以帮我吗?

4

2 回答 2

3

根据@DanielVérité 的建议,我实现了一个plpgsql函数,该函数将字符串替换为 type 的二进制字符串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)
于 2013-07-04T10:18:46.207 回答
2

转换为text和转换回的问题bytea是,如果替换字符串涉及字符串中的引用字节,它将不起作用。让我们看一个例子。

(我设置bytea_outputhex更好地查看文本,否则都是十六进制数字)

初始查询:

 with input(x) as (values (('\000\015Hello World\000\015Hello World'::bytea)))
  select replace(x::text, 'World', 'Jenny')::bytea from input;

结果很好:

                代替                 
--------------------------------------
 \000\015你好珍妮\000\015你好珍妮
(1 行)

但是,如果尝试使用想要替换字符的修改0版本1

with input(x) as (values (('\000\015Hello 0orld\000\015Hello 0orld'::bytea)))
  select replace(x::text, '0', '1')::bytea from input;

结果是:

                代替                 
--------------------------------------
 IMHello 1orldIMHello 1orld

而期望的结果是:\000\015Hello 1orld\000\015Hello 1orld. 发生这种情况是因为中间表示\000\015被替换为\111\115

于 2013-07-02T15:00:48.317 回答