[英]How to call a function in regexp_replace with matches?
我想在regexp_replace
函數中使用一些處理函數而不是replacement text
。 是否可以使用匹配作為參數的函數,例如:
SELECT REGEXP_REPLACE( description, '\[([is]?:?)(\d+)\]', some_custom_function(\1, \2), 'gi' )
FROM some_table
WHERE id = 123;
當然,反向引用\\1
和\\2
在這里不起作用,但是有什么方法可以使用變量代替它們嗎?
背景: description
可能包含多個具有[12345]
或[i:12345]
或[s:12345]
等模式的字符串,我想將此類匹配處理為高級字符串,因此我認為最好的方法是編寫一個自定義函數並使用regex_replace
匹配調用它。 我只是沒有在文檔中找到,我怎么能使用匹配作為變量/參數。 這是可能的還是實現我的目標的更好方法?
示例description
字段:
Lorem ipsum dolor sit amet [123], consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et [234] magna aliqua.
期望的輸出:
Lorem ipsum dolor sit amet "one-two-three", consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et "two-three-four" magna aliqua.
創建一個帶有文本參數的函數,例如:
create or replace function the_function(text, text)
returns text language sql as $$
select format('=replacement of %s and %s=', $1, $2)
$$;
並在regexp_replace()
使用它:
select regexp_replace(
description,
'\[([is]?:?)(\d+)\]',
the_function('\1', '\2'),
'gi')
from some_table
where id = 123;
這可能是你想要做的:
CREATE OR REPLACE FUNCTION my_replace(description TEXT)
RETURNS TEXT AS $$
SELECT string_agg(concat(l, some_custom_function(u[1], u[2])), '')
FROM ROWS FROM (
regexp_split_to_table(description, '\[(?:([is]):)?(\d+)\]', 'i'),
regexp_matches(description, '\[(?:([is]):)?(\d+)\]', 'gi')
) AS m(l, u)
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
我已將您的正則表達式從\\[([is]?:?)(\\d+)\\]
更改為\\[(?:([is]):)?(\\d+)\\]
以便您不匹配[i123]
或[:123]
。 這也導致“前綴”為NULL
而不是''
匹配[123]
。 如果這不是您的意圖,請還原為您的原始版本。
自定義函數示例:
CREATE OR REPLACE FUNCTION some_custom_function(prefix TEXT, number TEXT)
RETURNS TEXT AS $$
SELECT concat((upper(prefix) || '='), CASE number
WHEN '123' THEN '"one-two-three"'
WHEN '234' THEN '"two-three-four"'
ELSE CASE
WHEN number IS NOT NULL THEN '#foo'
END
END)
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
使用 no、小寫和大寫“前綴”進行測試:
SELECT unnest, my_replace(unnest)
FROM unnest(array[$$Lorem ipsum dolor sit amet [123], consectetur adipiscing elit [42],
sed do eiusmod [i:123] tempor incididunt ut labore et [S:234] magna aliqua.$$])
結果是:
Lorem ipsum dolor 坐 amet "一二三", consectetur adipiscing elit #foo,
sed do eiusmod I="one-2-3" tempor incididunt ut laboure et S="two-3-4" magna aliqua.
試試看: db<>fiddle
它基本上是這樣工作的:
regexp_split_to_table
和regexp_matches
文檔:
這是可能的還是實現我的目標的更好方法?
我建議只為此使用用戶定義的函數並使用解析方法迭代字符,而不是嘗試將其合並到正則表達式中。
下面是一個概念證明。 通過使用值及其替換表而不是對它們進行硬編碼,有改進的余地,如果有更多值,這將更清晰,當然也是必要的 - 如果需要,請在評論中告訴我。
CREATE OR REPLACE FUNCTION replaceDescription(description TEXT)
RETURNS TEXT
LANGUAGE PLPGSQL
AS
$$
DECLARE
pos INT := 1;
chr CHAR;
parsing BOOLEAN := FALSE;
BEGIN
WHILE pos <= CHAR_LENGTH(description) LOOP
chr := SUBSTRING(description, pos, 1);
IF chr = '[' THEN
parsing := TRUE;
ELSIF chr = ']' THEN
parsing := FALSE;
ELSIF parsing THEN
IF chr = '1' THEN
description := CONCAT(LEFT(description, pos - 1),
'one-',
RIGHT(description, CHAR_LENGTH(description) - pos));
pos := pos + 3;
ELSIF chr = '2' THEN
description := CONCAT(LEFT(description, pos - 1),
'two-',
RIGHT(description, CHAR_LENGTH(description) - pos));
pos := pos + 3;
ELSIF chr = '3' THEN
description := CONCAT(LEFT(description, pos - 1),
'three-',
RIGHT(description, CHAR_LENGTH(description) - pos));
pos := pos + 5;
ELSIF chr = '4' THEN
description := CONCAT(LEFT(description, pos - 1),
'four-',
RIGHT(description, CHAR_LENGTH(description) - pos));
pos := pos + 4;
END IF;
END IF;
pos := pos + 1;
END LOOP;
RETURN REPLACE(description, '-]', ']');
END;
$$;
Reextester 演示: https ://rextester.com/IBGE47544
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.