Как выполнить интерполяцию строк для текстового шаблона с именованными местозаполнителями?

Как можно выполнить интерполяцию строк с помощью PLSQL?

Дан шаблон с именованными параметрами, заключенными в фигурные скобки, затем именованные параметры заменяются на переменные. То есть, похожую функциональность Интерполяция строк на C#. Литерал в фигурных скобках {placeholder} служит как местозаменитель, а двойные фигурные скобки для экранирования литерала {{leave me}}.

Упрощённый пример для понимания, что хотелось бы:

DECLARE 
    v_template NVARCHAR2(500) := 
        '{name} говорит: Меня зовут {name}, мне {age}. Да-да, мне {age}!'|| 
        'Забытый ключ {somekey}. Оставте как есть {{name}}, {{age}}. А точка? {age}]';
    v_output NVARCHAR2(1000); 
    TYPE ty_dictionary IS TABLE OF NVARCHAR2(1000) INDEX BY VARCHAR2(200);
    v_vars ty_dictionary;
BEGIN
    v_vars('name') := 'Вася';
    v_vars('age')  := '13;'
    
    v_output:= pkg_interpolation.fn_format(v_template, v_vars);
    dbms_output.put_line('output: ' || v_output);
END;

Свободный перевод вопроса How to perform string interpolation in Oracle PLSQL and SQL. Given a text template with named placeholders от участника @Rax


Ответы (1 шт):

Автор решения: 0xdb

Воспроизводимый пример для реализации:

declare 
    type vararg is table of varchar2 (96) index by varchar2 (32);
    
    function format (template varchar2, args vararg) return varchar2 is
        key varchar2 (32);
        ret varchar2  (32767) := template;
        pattern varchar2 (32) := '(^|[^{]){(\w+)}([^}]|$)';
    begin
        <<substitute>> loop
            key := regexp_substr  (ret, pattern, 1, 1, null, 2);
            exit substitute when key is null;
            ret := regexp_replace (ret, pattern, 
                '\1'||case when args.exists (key) then args (key) else '?'||key||'?' end||
                '\3', 1, 1);
        end loop;
        return replace (replace (ret, '{{','{'), '}}', '}');
    end;
begin
    dbms_output.put_line ('output: '||format (
        '{name} говорит: Меня зовут {name}, мне {age}. Да-да, мне {age}!'||chr(10)|| 
        'Забытый ключ {somekey}. Оставте как есть {{name}}, {{age}}. А точка? {age}',
        vararg ('name' => 'Вася', 
                'age'  => to_char (13))));
end;
/

Результат:

Вася говорит: Меня зовут Вася, мне 13. Да-да, мне 13!
Забытый ключ ?somekey?. Оставте как есть {name}, {age}. А точка? 13


Свободный перевод ответа от участника @0xdb

→ Ссылка