簡體   English   中英

如何使用匹配調用 regexp_replace 中的函數?

[英]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

它基本上是這樣工作的:

  1. 將文本拆分/解壓縮為非匹配項和匹配項。
  2. 映射它們中的每一個。
  3. 將它們聚合/壓縮回文本。

regexp_split_to_tableregexp_matches文檔:

這是可能的還是實現我的目標的更好方法?

我建議只為此使用用戶定義的函數並使用解析方法迭代字符,而不是嘗試將其合並到正則表達式中。

下面是一個概念證明。 通過使用值及其替換表而不是對它們進行硬編碼,有改進的余地,如果有更多值,這將更清晰,當然也是必要的 - 如果需要,請在評論中告訴我。

SQL

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM