Я пытаюсь выполнить условную замену в одном операторе regexp_replace.
Например, если у меня есть строка 'Dog Cat Donkey', я хотел бы иметь возможность заменить 'Dog' на 'BigDog', 'Cat' на 'SmallCat' и 'Donkey 'на 'MediumDonkey', чтобы получить следующее:
'BigDog SmallCat MediumDonkey'
Я могу сделать это там, где все имеют префикс со словом Big, но не могу заменить его условно.
У меня сейчас есть это
select regexp_replace('Dog Cat Donkey', '(Cat)|(Dog)|(Donkey)', ' Big\1\2\3')
from dual
но, конечно, это возвращает только BigDog BigCat BigDonkey.
Я понимаю, что это не лучший способ сделать это, но возможно ли это?
Разве вы не можете использовать несколько выражений, таких как Bigs Dog|Wolf|Dingo, Smalls, например Cat|Persian, и Mediums Donkey|Horse? Если вы не можете выполнить обратный вызов, значит, это невозможно сделать сразу. Конечно, вы также можете добавить границы вокруг чередований, например, слово \b(list)\b и пробел (?<!\S)(list)(?!\S), если это необходимо.


Вы не думали просто сделать несколько replace()?
select replace(replace(replace(str, 'Dog', 'BigDog'), 'Cat', 'SmallCat'), 'Donkey', 'MediumDonkey')
Я понимаю, что regexp_replace() действительно мощный. И он мог бы это сделать. Но я не уверен, что это лучшее решение с точки зрения выражения того, что вы делаете.
Я полностью согласен! Это разрешить офисный аргумент о возможности. :)
Если одно слово является подстрокой другого, с этим подходом могут возникнуть проблемы.
@ WiktorStribiżew. . . То же самое можно сказать и об исходном регулярном выражении OP.
@GordonLinoff Нет, потому что регулярное выражение обрабатывает строку только один раз.
Запрос -
select listagg(final_str,' ') within group (order by sort_str) as output from (
SELECT
CASE LST
WHEN 'Dog' THEN 'BigDog'
WHEN 'Cat' THEN 'SmallCat'
WHEN 'Donkey' THEN 'MediumDonkey'
END AS final_str,
CASE LST
WHEN 'Dog' THEN 1
WHEN 'Cat' THEN 2
WHEN 'Donkey' THEN 3
END AS sort_str
from (
SELECT
trim(REGEXP_SUBSTR('Dog Cat Donkey', '(\S*)(\s*)', 1, LEVEL)) AS LST
FROM
DUAL
CONNECT BY
REGEXP_SUBSTR('Dog Cat Donkey', '(\S*)(\s*)', 1, LEVEL) IS NOT NULL
));
Выход -
BigDog SmallCat MediumDonkey
Для условной замены через REGEX_REPLACE?
Теперь вы можете сделать это, повторяя это для каждой другой строки замены.
Но вы все равно можете использовать | (ИЛИ) в 1 группе захвата, чтобы изменить более 1 слова для той же строки замены.
И как указал Гордон Линофф. На самом деле вам не нужен REGEX_REPLACE, когда обычного REPLACE достаточно для сопоставления одного слова.
select regexp_replace(
regexp_replace(
regexp_replace( str,
'(Dog|Snoopy)', 'Big\1')
,'(Cat|Feline)', 'Small\1')
,'(Donkey|Ass)', 'Medium\1')
from (select 'You Ass, that is not a Dog, but a Cat on a Donkey.' as str from dual);
Возврат:
You MediumAss, that is not a BigDog, but a SmallCat on a MediumDonkey.
Однако обратите внимание, что при использовании канала в регулярном выражении порядок имеет значение. Поэтому, если некоторые слова начинаются одинаково, лучше расположить их в порядке убывания длины. Пример:
select
regexp_replace(str, '(foo|foobar)', '[\1]') as foo_foobar,
regexp_replace(str, '(foobar|foo)', '[\1]') as foobar_foo
from (select 'foo foobar' as str from dual);
Возврат:
FOO_FOOBAR FOOBAR_FOO
--------------- ---------------
[foo] [foo]bar [foo] [foobar]
Вы можете только условно заменить в регулярном выражении Boost. Ни в коем случае с регулярным выражением Oracle.