I have seen from from oracle documentation I can do a|b which will match all instances of character 'a 'or character 'b'. I wondered if it was possible in regexp to have 'a' and not 'b' e.g. match all instances of 'a' except where a is followed by 'b'.
so with these 3 strings
AAAA
ACAD
AAAB
I want to match 1 and 2 but not 3.
You could try:
with x as (
select 'AAAA' as str from dual
union all
select 'ACAD' as str from dual
union all
select 'AAAB' as str from dual
)
select * from x
where regexp_like(str, '[aA][^bB]')
and NOT regexp_like(str, '[aA][bB]')
Output:
AAAA
ACAD
Note: If you don't care if A is followed by some other non-B char, you can simply do:
with x as (
select 'AAAA' as str from dual
union all
select 'ACAD' as str from dual
union all
select 'AAAB' as str from dual
)
select * from x
where regexp_like(str, '[aA]')
and NOT regexp_like(str, '[aA][bB]')
which would match "AAAA" or "XYZA"
Related
I've seen examples of how to separate comma-separated strings into rows like this:
select distinct id, trim(regexp_substr(value,'[^,]+', 1, level) ) value, level
from tbl1
connect by regexp_substr(value, '[^,]+', 1, level) is not null
order by id, level;
but, my question is, how do I do this on double quote and comma delimited strings?
Ex: the above works for strings like "1,2,3,4,5,6,7", but what about "1","2","3","4,5","6,7,8","9" so that the rows end up like:
1
2
3
4,5
6,7,8
9
edit: I'm on Oracle 11.2.0.4, 11gR2.
There is a hack. Replace the pattern "," with # and use it in regular expression.It works like a charm.
Input String : "1","2","3","4,5","6,7,8","9","Ant,B","Gradle","E,F","G"(Can be number/Character doesn't matter)
with temp as (
select replace(replace('"1","2","3","4,5","6,7,8","9","Ant,B","Gradle","E,F","G"','","','#'),'"') Colmn from dual
)
SELECT trim(regexp_substr(str, '[^#]+', 1, level)) str
FROM (SELECT Colmn str FROM temp) t
CONNECT BY instr(str, '#', 1, level - 1) > 0
Output :
STR
1
2
3
4,5
6,7,8
9
Ant,B
Gradle
E,F
G
10 rows
Refer DBFiddle link for demo.
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=d09c326f614d10f5d3c407fdfd3a44c5
here is the another solution.it must be working all string with have number.
i used number values index as base.
with temp as (
select '"1","2","3",x"4,5","6,73,8","9"' Colmn from dual
)
SELECT regexp_substr(Colmn, '\d{1}', REGEXP_INSTR(Colmn, '\d{1}', REGEXP_INSTR(Colmn, '\d{1}') ,level),1 ) from temp
CONNECT BY REGEXP_COUNT (Colmn,'\d{1}')+1> level
From stack overflow, I got the standard reg expression
to eliminate -
a) special characters
b) digits
c) more than 2 spaces to single space
to include -
d) - (hyphen)
e) ' (single quote)
SELECT ID, REGEXP_REPLACE(REGEXP_REPLACE(forenames, '[^A-Za-z-]', ' '),'\s{2,}',' ') , REGEXP_REPLACE(REGEXP_REPLACE(surname, '[^A-Za-z-]', ' '),'\s{2,}',' ') , forenames, surname from table1;
Instead of 2 functions how to get the result in single function?
to include '(single quote) \' is not working in regexp_replace.
Thanks.
Oracle Setup:
CREATE TABLE test_data ( id, value ) AS
SELECT 1, '123a45b£$- ''c45d#{e''' FROM DUAL
Query:
SELECT ID,
REGEXP_REPLACE(
value,
'[^a-zA-Z'' -]| +( )',
'\1'
)
FROM test_data
Output:
ID | REGEXP_REPLACE(VALUE,'[^A-ZA-Z''-]|+()','\1')
-: | :--------------------------------------------
1 | ab- 'cde'
db<>fiddle here
I have the following string my trying get out the 1111111 and 33333333333 with out the |
character
SELECT regexp_substr('7|1111111|2222222|33333333333|0||20140515|||false|0|0|0|0|0|','*[|]*[|][0-9]*')FROM dual
Using REGEXP_REPLACE may be a bit simpler;
SELECT REGEXP_REPLACE('7|1111111|2222222|33333333333|0||20140515|||false|0|0|0|0|0|',
'^([^|]*[|]){1}([^|]*).*$', '\2') FROM dual;
> 1111111
SELECT REGEXP_REPLACE('7|1111111|2222222|33333333333|0||20140515|||false|0|0|0|0|0|',
'^([^|]*[|]){3}([^|]*).*$', '\2') FROM dual;
> 33333333333
You can choose column by choosing how many pipes to skip in the {1} part.
A simple SQLfiddle to test with.
A short explanation of the regexp;
([^|]+[|]){3} -- Matches 3 groups of {optional characters}{pipe}
(\d*) -- Matches the next digit group (the one we want)
.* -- Matches the rest of the expression
What we want is the second paranthesized group, that is, we replace the whole string by the back reference \2.
Because "|" separators always present it's simpler to extract fields with simple substring function rather than using regular expressions.
Just find positions of corresponding separators in source string and extract content between them:
with test_data as (
select
'7|1111111|2222222|33333333333|0||20140515|||false|0|0|0|0|0|ABC' as s,
8 as field_number -- test 1, 3, 8, 10 and 16
from dual
)
select
field_number,
substr(
s,
decode( field_number,
1,1,
instr(s,'|',1,field_number - 1) + 1
),
(
decode( instr(s,'|',1,field_number),
0, length(s)+ 1,
instr(s,'|',1,field_number)
)
-
decode( field_number,
1, 1,
instr(s,'|',1,field_number - 1) + 1
)
)
) as field_value
from
test_data
SQLFiddle
This variant works with empty fields, non-numeric fields and so on.
Possible simplification with appending additional separators to the start and the end of the string:
with test_data as (
select
(
'|' ||
'7|1111111|2222222|33333333333|0||20140515|||false|0|0|0|0|0|ABC' ||
'|'
) as s, -- additional separators appended before and after original string
10 as field_number -- test 1, 3, 8, 10 and 16
from dual
)
select
field_number,
substr(
s,
instr(s, '|', 1, field_number) + 1,
(
instr(s, '|', 1, field_number + 1)
-
(instr(s, '|', 1, field_number) + 1)
)
) as field_value
from
test_data
;
SQLFiddle
How to find out the index of the first number encountered in the reverse direction of a string?
For example: 'CUSTOMC23VBA' and 'CUSTOMC245BA'.
So, function should return as '2' or '3' from reverse or the index value as '9' or '10'.
I could get the value by hard-coding the SUBSTR('CUSTOMC23VBA', -3) but I would want it to be generic as regular expressions.
You can try:
select regexp_instr(reverse('CUSTOM123XYZ'), '[[:digit:]]',1,1) from dual
Output: 4
Zero based index would be:
select regexp_instr(reverse('CUSTOM123XYZ'), '[[:digit:]]',1,1)-1 from dual
Output: 3
If you want the rest of the string from the last number, you can use substr and take advantage of the negative position to count from end of string:
select substr('CUSTOM123XYZ', -1 * (regexp_instr(reverse('CUSTOM123XYZ'), '[[:digit:]]',1,1)-1)) from dual;
Output: XYZ
An example testing multiple input strings:
with d as (
select 'CUSTOM123XYZ' as input_str from dual
union
select 'CUSTOM123XZ' as input_str from dual
union
select 'CUSTOM 1 X 3YZ' as input_str from dual
)
select input_str,
substr(input_str, -1 * (regexp_instr(reverse(input_str), '[[:digit:]]',1,1)-1)) as result
from d
Output:
INPUT_STR RESULT
CUSTOM 1 X 3YZ YZ
CUSTOM123XYZ XYZ
CUSTOM123XZ XZ
Is there only one number in the string? if so, you could go for something like this:
select REGEXP_REPLACE('CUSTOMC23VBA', '[[:alpha:]]','') from dual
But this will fail when there are multiple numbers in the string.
How do I use reg expression to found last number in a string and then everything on the right hand side in to column c1 and from the last number everything on the left + 1 character go into column c2 ?
e.g 1
string = 1234john4345 this is a test.
Result
c1 = 1234john4345
c2 = this is a test.
e.g 2
string = 1234john4345a this is a test.
Result
c1 = 1234john4345a
c2 = this is a test.
select test
--Group 1: Match everything up to the last digit, and one other character
--Group 2: Everything after group 1
,regexp_replace(test, '(.*[[:digit:]].)(.*)', '\1') c1
,regexp_replace(test, '(.*[[:digit:]].)(.*)', '\2') c2
from
(
select '1234john4345 this is a test.' test from dual union all
select '1234john4345a this is a test' test from dual
);