Conditional regexp_replace Oracle / PLSQL - sql

I'm trying to do a conditional replace within one regexp_replace statement.
For example, if I have the string, 'Dog Cat Donkey', I would like to be able to replace 'Dog' with 'BigDog', 'Cat' with 'SmallCat' and 'Donkey' with 'MediumDonkey' to get the following:
'BigDog SmallCat MediumDonkey'
I can do it where all are prefixed with the word Big but can't seem to make it replace conditionally.
I currently have this
select regexp_replace('Dog Cat Donkey', '(Cat)|(Dog)|(Donkey)', ' Big\1\2\3')
from dual
but of course this only returns 'BigDog BigCat BigDonkey'.
I'm aware this isn't the best way of doing this but is it possible?

Have you considered just doing multiple replace()s?
select replace(replace(replace(str, 'Dog', 'BigDog'), 'Cat', 'SmallCat'), 'Donkey', 'MediumDonkey')
I get that regexp_replace() is really powerful. And it might be able to do this. But I'm not sure that's a better solution in terms of expressing what you are doing.

Query -
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
));
Output -
BigDog SmallCat MediumDonkey

For conditional replacement via REGEX_REPLACE?
Then currently you can do this by repeating it for each different replacement string.
But you could still use the | (OR) within the 1 capture group to change more than 1 word for the same replacement string.
And as Gordon Linoff pointed out.
You don't really need a REGEX_REPLACE when a normal REPLACE is sufficient to match a single word.
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);
Returns:
You MediumAss, that is not a BigDog, but a SmallCat on a MediumDonkey.
Do note however that when using the pipe in a regex, that the order matters.
So if some words start the same then better put them in order of descending length.
Example:
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);
Returns:
FOO_FOOBAR FOOBAR_FOO
--------------- ---------------
[foo] [foo]bar [foo] [foobar]

Related

How to get first string after character Oracle SQL

I'm trying to get first string after a character.
Example is like
ABCDEF||GHJ||WERT
I need only
GHJ
I tried to use REGEXP but i couldnt do it.
Can anyone help me with please?
Thank you
Somewhat simpler:
SQL> select regexp_substr('ABCDEF||GHJ||WERT', '\w+', 1, 2) result from dual;
^
RES |
--- give me the 2nd "word"
GHJ
SQL>
which reads as: give me the 2nd word out of that string. Won't work properly if GHJ consists of several words (but that's not what your example suggests).
Something like I interpret with a separator in place, In this case it is || or | example is with oracle database
-- pattern -- > [^] represents non-matching character and + for says one or more character followed by ||
-- 3rd parameter --> starting position
-- 4th parameter --> nth occurrence
WITH tbl(str) AS
(SELECT 'ABCDEF||GHJ||WERT' str FROM dual)
SELECT regexp_substr(str
,'[^||]+'
,1
,2) output
FROM tbl;
I think the most general solution is:
WITH tbl(str) AS (
SELECT 'ABCDEF||GHJ||WERT' str FROM dual UNION ALL
SELECT 'ABC|DEF||GHJ||WERT' str FROM dual UNION ALL
SELECT 'ABClDEF||GHJ||WERT' str FROM dual
)
SELECT regexp_replace(str, '^.*\|\|(.*)\|\|.*', '\1')
FROM tbl;
Note that this works even if the individual elements contain punctuation or a single vertical bar -- which the other solutions do not. Here is a comparison.
Presumably, the double vertical bar is being used for maximum flexibility.
You should use regexp_substr function
select regexp_substr('ABCDEF||GHJ||WERT ', '\|{2}([^|]+)', 1, 1, 'i', 1) str
from dual;
STR
---
GHJ

ORACLE regexp_substr extract everything after specific char

How to get rest of string after specific char?
I have a string 'a|b|c|2|:x80|3|rr|' and I would like to get result after 3rd occurance of |. So the result should be like 2|:x80|3|rr|
The query
select REGEXP_SUBSTR('a|b|c|2|:x80|3|rr|','[^|]+$',1,4)
from dual
Returned me NULL
Use SUBSTR / INSTR combination
WITH t ( s ) AS (
SELECT 'a|b|c|2|:x80|3|rr|'
FROM dual
) SELECT substr(s,instr(s,'|',1,3) + 1)
FROM t;
Demo
REGEXP_REPLACE() will do the trick. Skip 3 groups of anything followed by a pipe, then replace with the 2nd group, which is the rest of the line (anchored to the end).
SQL> select regexp_replace('a|b|c|2|:x80|3|rr|', '(.*?\|){3}(.*)$', '\2') trimmed
2 from dual;
TRIMMED
------------
2|:x80|3|rr|
SQL>
I suggest a nice by long way by using regexp_substr, regexp_count and listagg together as :
select listagg(str) within group (order by lvl)
as "Result String"
from
(
with t(str) as
(
select 'a|b|c|2|:x80|3|rr|' from dual
)
select level-1 as lvl,
regexp_substr(str,'(.*?)(\||$)',1,level) as str
from dual
cross join t
connect by level <= regexp_count('a|b|c|2|:x80|3|rr|','\|')
)
where lvl >= 3;
Rextester Demo
If you use oracle 11g and above you can specify a subexpression to return like this:
select REGEXP_SUBSTR('a|b|c|2|:x80|3|rr|','([^|]+\|){3}(.+)$',1,1,null,2) from dual
Erkko,
You need to use the combination of SUBSTR and REGEXP_INSTR OR INSTR.
Your query will look like this. (Without Regex)
SELECT SUBSTR('a|b|c|2|:x80|3|rr|',INSTR('a|b|c|2|:x80|3|rr|','|',1,3)+1) from dual;
Your query will look like this. (With Regex as you want to use)
SELECT SUBSTR('a|b|c|2|:x80|3|rr|',REGEXP_INSTR('a|b|c|2|:x80|3|rr|','\|',1,3)+1) from dual;
Explanation:
First, you will need to find the place of the string you want as you mentioned. So in your case | comes at place 6. So that +1 would be your position to start to substring.
Second, from the original string, substring from that position+1 to unlimited.(Where your string ends)
Example:
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=6fd782db95f575201eded084493232ee

Oracle Regexp_substr String

I have String like a123bcd-e2343fg-hij-dfgh
and I want OUTPUT e2343fg-hij-dfgh using Regular_expression in oracle.
select regexp_substr('abcd-efg-hij','-[^-]+'1) from dual;
You may apply regexp_substr with [^-]+[-^] pattern and then ltrim as :
select ltrim('a123bcd-e2343fg-hij-dfgh',
regexp_substr('a123bcd-e2343fg-hij-dfgh','[^-]+[-^]')) as output_string
from dual;
or better to call with bind variable :
select ltrim('&str', regexp_substr('&str','[^-]+[-^]')) as output_string
from dual;
where &str may be replaced with a123bcd-e2343fg-hij-dfgh after prompted.
Rextester Demo
Why regular expression, when a trivial SUBSTR + INSTR does the job nicely & quickly? True, it will look smarter, but I can't see any other benefit.
SQL> with test (col) as
2 (select 'a123bcd-e2343fg-hij-dfgh' from dual)
3 select substr(col, instr(col, '-') + 1) result
4 from test;
RESULT
----------------
e2343fg-hij-dfgh
SQL>
select substr('abcd-efg-hij',
regexp_instr('abcd-efg-hij','-[^-]+')+1,length('abcd-efg-hij'))
from dual;
try this
For the sake of argument, regexp_replace works too. This regex matches anything up to and including the first dash, and remembers the rest which it returns.
with tbl(str) as (
select 'a123bcd-e2343fg-hij-dfgh' from dual
)
select regexp_replace(str, '^.*?-(.*)', '\1')
from tbl;
Keep in mind if regexp_substr() does not find a match, it returns NULL but if regexp_replace() does not find a match it return the original string.

Using REGEXP_SUBSTR with Strings Qualifier

Getting Examples from similar Stack Overflow threads,
Remove all characters after a specific character in PL/SQL
and
How to Select a substring in Oracle SQL up to a specific character?
I would want to retrieve only the first characters before the occurrence of a string.
Example:
STRING_EXAMPLE
TREE_OF_APPLES
The Resulting Data set should only show only STRING_EXAM and TREE_OF_AP because PLE is my delimiter
Whenever i use the below REGEXP_SUBSTR, It gets only STRING_ because REGEXP_SUBSTR treats PLE as separate expressions (P, L and E), not as a single expression (PLE).
SELECT REGEXP_SUBSTR('STRING_EXAMPLE','[^PLE]+',1,1) from dual;
How can i do this without using numerous INSTRs and SUBSTRs?
Thank you.
The problem with your query is that if you use [^PLE] it would match any characters other than P or L or E. You are looking for an occurence of PLE consecutively. So, use
select REGEXP_SUBSTR(colname,'(.+)PLE',1,1,null,1)
from tablename
This returns the substring up to the last occurrence of PLE in the string.
If the string contains multiple instances of PLE and only the substring up to the first occurrence needs to be extracted, use
select REGEXP_SUBSTR(colname,'(.+?)PLE',1,1,null,1)
from tablename
Why use regular expressions for this?
select substr(colname, 1, instr(colname, 'PLE')-1) from...
would be more efficient.
with
inputs( colname ) as (
select 'FIRST_EXAMPLE' from dual union all
select 'IMPLEMENTATION' from dual union all
select 'PARIS' from dual union all
select 'PLEONASM' from dual
)
select colname, substr(colname, 1, instr(colname, 'PLE')-1) as result
from inputs
;
COLNAME RESULT
-------------- ----------
FIRST_EXAMPLE FIRST_EXAM
IMPLEMENTATION IM
PARIS
PLEONASM

Extract string within delimiters

I have a string {1:F01BPHKPLPKXXX0000000000} from which I need to extract 1:F01BPHKPLPKXXX0000000000 using regex_substr. Can you please help me with this ?
Why use REGEXP_SUBSTR? Using pistol to kill a mouse?
You just need to TRIM those braces.
SQL> WITH DATA AS(
2 SELECT q'[{1:F01BPHKPLPKXXX0000000000}]' STR FROM DUAL)
3 select rtrim(ltrim(str,'{'),'}') str from data
4 /
STR
--------------------------
1:F01BPHKPLPKXXX0000000000
SQL>
What about this:
select regexp_replace('{1:F01BPHKPLPKXXX0000000000}', '{(.*)}', '\1')
from dual
It takes everything between the brackets and outputs that.
This can be much easier if you ask me, using substr:
select substr(var, 2, length(var)-2)
from (select '{1:F01BPHKPLPKXXX0000000000}' var from dual)
Try the following:
SELECT REGEXP_SUBSTR('{1:F01BPHKPLPKXXX0000000000}', '[^{].*[^}]') FROM DUAL
Share and enjoy.
I would just use regexp_replace. I just use the alternation operator, |, so that I ask to replace { at the beginning (using the anchor ^) and } at the end of the string (using the anchor $).
SCOTT#dev> WITH a_tab AS
2 (SELECT '{1:F01BPHKPLPKXXX0000000000}' a_col FROM dual
3 )
4 SELECT regexp_replace (a_col, '^{|}$') FROM a_tab
5 /
REGEXP_REPLACE(A_COL,'^{|}$')
==========================
1:F01BPHKPLPKXXX0000000000