Oracle SQL获取括号中的最后一个字符串(括号中可能也包含括号)
我正在使用此查询:Oracle SQL获取括号中的最后一个字符串(括号中可能也包含括号),sql,regex,oracle,substring,Sql,Regex,Oracle,Substring,我正在使用此查询: SELECT strain.id, TRIM(SUBSTR(strain.name, 1, INSTR(strain.name, '[')-1)) AS name FROM species_strain strain 上面的查询提供了如下内容: id name ----------------------------------------------- 100 CfwHE3 (HH3d) Jt1 (CD-1) 101 4GSdg-3t 22sfG/J (md
SELECT strain.id, TRIM(SUBSTR(strain.name, 1, INSTR(strain.name, '[')-1)) AS name
FROM species_strain strain
上面的查询提供了如下内容:
id name
-----------------------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID)
103 B29fj;jfos x11 (tmos (line x11))
104 B29;CD (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J --------> I don't want to get (te3x)
(CD-1)
(mdx (fq) KO)
(SCID)
(tmos (line x11))
(Atm (line G5))
我需要一个正则表达式,它将为我提供最后一组括号的内容(其中可能包含也可能不包含1组或多组括号)-这需要在字符串的末尾。如果它在字符串的中间,那么我不想要它。< /P>
我想得到的是:
id name
-----------------------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID)
103 B29fj;jfos x11 (tmos (line x11))
104 B29;CD (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J --------> I don't want to get (te3x)
(CD-1)
(mdx (fq) KO)
(SCID)
(tmos (line x11))
(Atm (line G5))
因此,如果我复制并粘贴我的整个查询,我有以下内容,但这不考虑其中的括号:
SELECT DISTINCT REGEXP_SUBSTR(strain.name, '\(.*?\)', 1, REGEXP_COUNT(strain.name, '\(.*?\)')) AS name
FROM (
SELECT strain.id, TRIM(SUBSTR(strain.name, 1, INSTR(strain.name, '[')-1)) AS name
FROM species_strain strain
) strain
WHERE INSTR(strain.name, '(', 1, 1) > 0
查询以某种方式工作,但如果我在主括号内得到另一组括号,它就会中断,并丢失一些数据。它返回类似于:
(CD-1)
(mdx (fq) ---------> missing KO)
(SCID)
(tmos (line x11) ---------> missing )
(Atm (line G5) ---------> missing )
附加要求
我忘了提到我需要的一组括号应该在末尾。如果后面还有其他字符,我就不想要了。我在我的示例中添加了另一行。如果只有一个嵌套,那么以下操作应该有效:
regexp_substr(col, '[(]([^()]*|[(][^()]*[)])+[)]$', 1, 1)
这满足了您问题中的所有示例,但不允许任意嵌套括号。您应该注意,Oracle正则表达式没有PCRE或.NET正则表达式强大。因此,您只能使用正则表达式来匹配指定的嵌套括号级别 以下正则表达式将匹配具有1个嵌套括号级别的字符串中的最后一个括号:
\([^()]*(\([^()]*\)[^()]*)*\)$
见
此正则表达式不会匹配Test(get(me)((me))
之类的字符串。我提供的模式将使用1个嵌套级别,它可以被增强以支持2个级别,并且它将比现在更不可读
详情:
-a\(
(
-除[^()]*
和(
之外的零个或多个字符)
-零次或多次出现:(\([^()]*\)[^()]*)*
a\(
(
-除[^()]*
和(
之外的零个或多个字符)
-结账\)
)
-除[^()]*
和(
之外的零个或多个字符)
-结账\)
)
-字符串的结尾$
regexp_substr(col_name, '\([^()]*(\([^()]*\)[^()]*)*\)$', 1, 1)
如果创建函数是一个选项,则以下函数将执行此任务:
create or replace
function fn_pars(p_text in varchar2) return varchar2 deterministic as
n_count pls_integer := 0;
begin
if p_text is null or instr(p_text, ')', -1) = 0
or p_text not like '%)' then
return null;
end if;
for i in reverse 1..length(p_text) loop
case substr(p_text, i, 1)
when ')' then n_count := n_count + 1;
when '(' then n_count := n_count - 1;
else null;
end case;
if n_count = 0 then
return substr(p_text, i);
end if;
end loop;
return p_text;
end fn_pars;
然后您可以测试它:
select text,
fn_pars(text)
from (
select 'B29fj;jfos x11 (tmos (line x11)) abc' text from dual union all
select 'B29fj;j(fos) x11 (tmos (line x11))' text from dual union all
select 'B29fj;j(fos) x11 (t(mo)s (line x11))' text from dual union all
select '' text from dual union all
select 'no parentheses' text from dual
)
结果:
Text fn_pars(text)
-----------------------------------------------------
B29fj;jfos x11 (tmos (line x11)) abc (null)
B29fj;j(fos) x11 (tmos (line x11)) (tmos (line x11))
B29fj;j(fos) x11 (t(mo)s (line x11)) (t(mo)s (line x11))
(null) (null)
no parentheses (null)
其中(null)表示无值。:)
该函数支持任何级别的嵌套。您还可以在同一级别嵌套多个括号。这适用于任何深度的嵌套括号: Oracle安装程序:
CREATE TABLE species_strain ( id, name ) AS
SELECT 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' FROM DUAL UNION ALL
SELECT 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' FROM DUAL UNION ALL
SELECT 102, 'Yf7mMjfel 7(tm1) (SCID)' FROM DUAL UNION ALL
SELECT 103, 'B29fj;jfos x11 (tmos (line x11))' FROM DUAL UNION ALL
SELECT 104, 'B29;CD (Atm (line G5))' FROM DUAL UNION ALL
SELECT 105, 'Ifkso30 jel-3' FROM DUAL UNION ALL
SELECT 106, 'data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)' FROM DUAL;
WITH tmp ( id, name, pos, depth ) AS (
SELECT id,
name,
LENGTH( name ),
1
FROM species_strain
WHERE SUBSTR( name, -1 ) = ')'
UNION ALL
SELECT id,
name,
pos - 1,
depth + CASE SUBSTR( name, pos - 1, 1 )
WHEN '(' THEN -1
WHEN ')' THEN +1
ELSE 0 END
FROM tmp
WHERE ( depth > 1
OR SUBSTR( name, pos -1, 1 ) <> '(' )
AND pos > 0
)
SELECT id,
MAX( name ) AS name,
MIN( SUBSTR( name, pos - 1 ) ) KEEP ( DENSE_RANK FIRST ORDER BY pos )
AS bracket
FROM tmp
GROUP BY id;
SELECT id,
name,
substr( name, start_pos ) AS bracket
FROM (
SELECT id,
name,
LAG( CASE WHEN bracket = '(' AND depth = 1 THEN pos END )
IGNORE NULLS OVER ( PARTITION BY id ORDER BY ROWNUM )
AS start_pos,
pos AS end_pos,
bracket,
depth
FROM (
SELECT id,
name,
COLUMN_VALUE AS pos,
SUBSTR( name, column_value, 1 ) AS bracket,
SUM( CASE SUBSTR( name, column_value, 1 ) WHEN '(' THEN 1 ELSE -1 END )
OVER ( PARTITION BY id ORDER BY ROWNUM ) AS depth
FROM species_strain s,
TABLE(
CAST(
MULTISET(
SELECT REGEXP_INSTR( s.name, '[()]', 1, LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( s.name, '[()]' )
) AS SYS.ODCINUMBERLIST
)
) t
WHERE SUBSTR( s.name, -1 ) = ')'
)
)
WHERE bracket = ')'
AND end_pos = LENGTH( name );
ID NAME BRACKET
---------- ------------------------------------------ ------------------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
106 data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1) (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)
with
species_str ( id, name) as (
select 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' from dual union all
select 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' from dual union all
select 102, 'Yf7mMjfel 7(tm1) (SCID)' from dual union all
select 103, 'B29fj;jfos x11 (tmos (line x11))' from dual union all
select 104, 'B29;CD (Atm (line G5))' from dual union all
select 105, 'Ifkso30 jel-3' from dual union all
select 106, '13GupSip (te3x) Blhas/J' from dual union all
select 151, '' from dual union all
select 152, 'try (this (and (this))) ok?' from dual union all
select 153, 'try (this (and (this)) ok?)' from dual union all
select 154, 'try (this (and) this (ok))?' from dual union all
select 155, 'try (this (and (this)' from dual union all
select 156, 'right grouping (includging ")")' from dual union all
select 157, 'try this out ) ( too' from dual
),
prep ( id, name, pos ) as (
select id, name, instr(name, ')', -1)
from species_str
),
rec ( id, name, str, len, prev_pos, new_pos, flag ) as (
select id, name, substr(name, 1, instr(name, ')', -1)),
pos, pos - 1, pos, null
from prep
union all
select id, name, str, len, new_pos,
instr(str, '(', -(len - new_pos + 2)),
case when length(replace(substr(str, new_pos), '(', '')) =
length(replace(substr(str, new_pos), ')', ''))
then 1 end
from rec
where prev_pos > 0 and flag is null
)
select id, name, case when flag = 1
then substr(name, prev_pos, len - prev_pos + 1) end as target
from rec
where flag = 1 or prev_pos <= 0 or name is null
order by id;
ID NAME TARGET
---------- -------------------------------- --------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J (te3x)
151
152 try (this (and (this))) ok? (this (and (this)))
153 try (this (and (this)) ok?) (this (and (this)) ok?)
154 try (this (and) this (ok))? (this (and) this (ok))
155 try (this (and (this) (this)
156 right grouping (includging ")")
157 try this out ) ( too
14 rows selected
查询1:
CREATE TABLE species_strain ( id, name ) AS
SELECT 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' FROM DUAL UNION ALL
SELECT 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' FROM DUAL UNION ALL
SELECT 102, 'Yf7mMjfel 7(tm1) (SCID)' FROM DUAL UNION ALL
SELECT 103, 'B29fj;jfos x11 (tmos (line x11))' FROM DUAL UNION ALL
SELECT 104, 'B29;CD (Atm (line G5))' FROM DUAL UNION ALL
SELECT 105, 'Ifkso30 jel-3' FROM DUAL UNION ALL
SELECT 106, 'data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)' FROM DUAL;
WITH tmp ( id, name, pos, depth ) AS (
SELECT id,
name,
LENGTH( name ),
1
FROM species_strain
WHERE SUBSTR( name, -1 ) = ')'
UNION ALL
SELECT id,
name,
pos - 1,
depth + CASE SUBSTR( name, pos - 1, 1 )
WHEN '(' THEN -1
WHEN ')' THEN +1
ELSE 0 END
FROM tmp
WHERE ( depth > 1
OR SUBSTR( name, pos -1, 1 ) <> '(' )
AND pos > 0
)
SELECT id,
MAX( name ) AS name,
MIN( SUBSTR( name, pos - 1 ) ) KEEP ( DENSE_RANK FIRST ORDER BY pos )
AS bracket
FROM tmp
GROUP BY id;
SELECT id,
name,
substr( name, start_pos ) AS bracket
FROM (
SELECT id,
name,
LAG( CASE WHEN bracket = '(' AND depth = 1 THEN pos END )
IGNORE NULLS OVER ( PARTITION BY id ORDER BY ROWNUM )
AS start_pos,
pos AS end_pos,
bracket,
depth
FROM (
SELECT id,
name,
COLUMN_VALUE AS pos,
SUBSTR( name, column_value, 1 ) AS bracket,
SUM( CASE SUBSTR( name, column_value, 1 ) WHEN '(' THEN 1 ELSE -1 END )
OVER ( PARTITION BY id ORDER BY ROWNUM ) AS depth
FROM species_strain s,
TABLE(
CAST(
MULTISET(
SELECT REGEXP_INSTR( s.name, '[()]', 1, LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( s.name, '[()]' )
) AS SYS.ODCINUMBERLIST
)
) t
WHERE SUBSTR( s.name, -1 ) = ')'
)
)
WHERE bracket = ')'
AND end_pos = LENGTH( name );
ID NAME BRACKET
---------- ------------------------------------------ ------------------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
106 data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1) (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)
with
species_str ( id, name) as (
select 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' from dual union all
select 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' from dual union all
select 102, 'Yf7mMjfel 7(tm1) (SCID)' from dual union all
select 103, 'B29fj;jfos x11 (tmos (line x11))' from dual union all
select 104, 'B29;CD (Atm (line G5))' from dual union all
select 105, 'Ifkso30 jel-3' from dual union all
select 106, '13GupSip (te3x) Blhas/J' from dual union all
select 151, '' from dual union all
select 152, 'try (this (and (this))) ok?' from dual union all
select 153, 'try (this (and (this)) ok?)' from dual union all
select 154, 'try (this (and) this (ok))?' from dual union all
select 155, 'try (this (and (this)' from dual union all
select 156, 'right grouping (includging ")")' from dual union all
select 157, 'try this out ) ( too' from dual
),
prep ( id, name, pos ) as (
select id, name, instr(name, ')', -1)
from species_str
),
rec ( id, name, str, len, prev_pos, new_pos, flag ) as (
select id, name, substr(name, 1, instr(name, ')', -1)),
pos, pos - 1, pos, null
from prep
union all
select id, name, str, len, new_pos,
instr(str, '(', -(len - new_pos + 2)),
case when length(replace(substr(str, new_pos), '(', '')) =
length(replace(substr(str, new_pos), ')', ''))
then 1 end
from rec
where prev_pos > 0 and flag is null
)
select id, name, case when flag = 1
then substr(name, prev_pos, len - prev_pos + 1) end as target
from rec
where flag = 1 or prev_pos <= 0 or name is null
order by id;
ID NAME TARGET
---------- -------------------------------- --------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J (te3x)
151
152 try (this (and (this))) ok? (this (and (this)))
153 try (this (and (this)) ok?) (this (and (this)) ok?)
154 try (this (and) this (ok))? (this (and) this (ok))
155 try (this (and (this) (this)
156 right grouping (includging ")")
157 try this out ) ( too
14 rows selected
下面的解决方案使用纯SQL(无过程/函数);它适用于任何级别的嵌套括号和“相同级别”括号;当输入为
null
,或者它不包含任何右括号,或者它包含一个右括号但最右括号不平衡时,它返回null
(在最右括号的左边没有左括号,因此这对括号是平衡的)
在最底部,我将显示仅当最右边的括号是输入字符串中的最后一个字符时返回“结果”所需的微小调整,否则返回null这是OP编辑的要求
我又创建了几个用于测试的输入字符串。请特别注意id=156
,在这种情况下,智能解析器不会“计数”字符串文本中的括号,或者以其他方式不是“正常”括号。我的解决方案没有走那么远——它对所有括号都一视同仁
策略是从最右边的括号(如果至少有一个)的位置开始,然后从那里一步一步地向左移动,只穿过左括号(如果有),并测试括号是否平衡。通过比较删除所有)
后“测试字符串”的长度与删除所有(
后的长度,可以很容易地做到这一点
好处:我可以不用正则表达式编写解决方案,只使用“标准”(非regexp)字符串函数。这将有助于快速编写
查询:
CREATE TABLE species_strain ( id, name ) AS
SELECT 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' FROM DUAL UNION ALL
SELECT 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' FROM DUAL UNION ALL
SELECT 102, 'Yf7mMjfel 7(tm1) (SCID)' FROM DUAL UNION ALL
SELECT 103, 'B29fj;jfos x11 (tmos (line x11))' FROM DUAL UNION ALL
SELECT 104, 'B29;CD (Atm (line G5))' FROM DUAL UNION ALL
SELECT 105, 'Ifkso30 jel-3' FROM DUAL UNION ALL
SELECT 106, 'data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)' FROM DUAL;
WITH tmp ( id, name, pos, depth ) AS (
SELECT id,
name,
LENGTH( name ),
1
FROM species_strain
WHERE SUBSTR( name, -1 ) = ')'
UNION ALL
SELECT id,
name,
pos - 1,
depth + CASE SUBSTR( name, pos - 1, 1 )
WHEN '(' THEN -1
WHEN ')' THEN +1
ELSE 0 END
FROM tmp
WHERE ( depth > 1
OR SUBSTR( name, pos -1, 1 ) <> '(' )
AND pos > 0
)
SELECT id,
MAX( name ) AS name,
MIN( SUBSTR( name, pos - 1 ) ) KEEP ( DENSE_RANK FIRST ORDER BY pos )
AS bracket
FROM tmp
GROUP BY id;
SELECT id,
name,
substr( name, start_pos ) AS bracket
FROM (
SELECT id,
name,
LAG( CASE WHEN bracket = '(' AND depth = 1 THEN pos END )
IGNORE NULLS OVER ( PARTITION BY id ORDER BY ROWNUM )
AS start_pos,
pos AS end_pos,
bracket,
depth
FROM (
SELECT id,
name,
COLUMN_VALUE AS pos,
SUBSTR( name, column_value, 1 ) AS bracket,
SUM( CASE SUBSTR( name, column_value, 1 ) WHEN '(' THEN 1 ELSE -1 END )
OVER ( PARTITION BY id ORDER BY ROWNUM ) AS depth
FROM species_strain s,
TABLE(
CAST(
MULTISET(
SELECT REGEXP_INSTR( s.name, '[()]', 1, LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( s.name, '[()]' )
) AS SYS.ODCINUMBERLIST
)
) t
WHERE SUBSTR( s.name, -1 ) = ')'
)
)
WHERE bracket = ')'
AND end_pos = LENGTH( name );
ID NAME BRACKET
---------- ------------------------------------------ ------------------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
106 data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1) (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)
with
species_str ( id, name) as (
select 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' from dual union all
select 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' from dual union all
select 102, 'Yf7mMjfel 7(tm1) (SCID)' from dual union all
select 103, 'B29fj;jfos x11 (tmos (line x11))' from dual union all
select 104, 'B29;CD (Atm (line G5))' from dual union all
select 105, 'Ifkso30 jel-3' from dual union all
select 106, '13GupSip (te3x) Blhas/J' from dual union all
select 151, '' from dual union all
select 152, 'try (this (and (this))) ok?' from dual union all
select 153, 'try (this (and (this)) ok?)' from dual union all
select 154, 'try (this (and) this (ok))?' from dual union all
select 155, 'try (this (and (this)' from dual union all
select 156, 'right grouping (includging ")")' from dual union all
select 157, 'try this out ) ( too' from dual
),
prep ( id, name, pos ) as (
select id, name, instr(name, ')', -1)
from species_str
),
rec ( id, name, str, len, prev_pos, new_pos, flag ) as (
select id, name, substr(name, 1, instr(name, ')', -1)),
pos, pos - 1, pos, null
from prep
union all
select id, name, str, len, new_pos,
instr(str, '(', -(len - new_pos + 2)),
case when length(replace(substr(str, new_pos), '(', '')) =
length(replace(substr(str, new_pos), ')', ''))
then 1 end
from rec
where prev_pos > 0 and flag is null
)
select id, name, case when flag = 1
then substr(name, prev_pos, len - prev_pos + 1) end as target
from rec
where flag = 1 or prev_pos <= 0 or name is null
order by id;
ID NAME TARGET
---------- -------------------------------- --------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J (te3x)
151
152 try (this (and (this))) ok? (this (and (this)))
153 try (this (and (this)) ok?) (this (and (this)) ok?)
154 try (this (and) this (ok))? (this (and) this (ok))
155 try (this (and (this) (this)
156 right grouping (includging ")")
157 try this out ) ( too
14 rows selected
满足OP(编辑)要求所需的变更:
CREATE TABLE species_strain ( id, name ) AS
SELECT 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' FROM DUAL UNION ALL
SELECT 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' FROM DUAL UNION ALL
SELECT 102, 'Yf7mMjfel 7(tm1) (SCID)' FROM DUAL UNION ALL
SELECT 103, 'B29fj;jfos x11 (tmos (line x11))' FROM DUAL UNION ALL
SELECT 104, 'B29;CD (Atm (line G5))' FROM DUAL UNION ALL
SELECT 105, 'Ifkso30 jel-3' FROM DUAL UNION ALL
SELECT 106, 'data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)' FROM DUAL;
WITH tmp ( id, name, pos, depth ) AS (
SELECT id,
name,
LENGTH( name ),
1
FROM species_strain
WHERE SUBSTR( name, -1 ) = ')'
UNION ALL
SELECT id,
name,
pos - 1,
depth + CASE SUBSTR( name, pos - 1, 1 )
WHEN '(' THEN -1
WHEN ')' THEN +1
ELSE 0 END
FROM tmp
WHERE ( depth > 1
OR SUBSTR( name, pos -1, 1 ) <> '(' )
AND pos > 0
)
SELECT id,
MAX( name ) AS name,
MIN( SUBSTR( name, pos - 1 ) ) KEEP ( DENSE_RANK FIRST ORDER BY pos )
AS bracket
FROM tmp
GROUP BY id;
SELECT id,
name,
substr( name, start_pos ) AS bracket
FROM (
SELECT id,
name,
LAG( CASE WHEN bracket = '(' AND depth = 1 THEN pos END )
IGNORE NULLS OVER ( PARTITION BY id ORDER BY ROWNUM )
AS start_pos,
pos AS end_pos,
bracket,
depth
FROM (
SELECT id,
name,
COLUMN_VALUE AS pos,
SUBSTR( name, column_value, 1 ) AS bracket,
SUM( CASE SUBSTR( name, column_value, 1 ) WHEN '(' THEN 1 ELSE -1 END )
OVER ( PARTITION BY id ORDER BY ROWNUM ) AS depth
FROM species_strain s,
TABLE(
CAST(
MULTISET(
SELECT REGEXP_INSTR( s.name, '[()]', 1, LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( s.name, '[()]' )
) AS SYS.ODCINUMBERLIST
)
) t
WHERE SUBSTR( s.name, -1 ) = ')'
)
)
WHERE bracket = ')'
AND end_pos = LENGTH( name );
ID NAME BRACKET
---------- ------------------------------------------ ------------------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
106 data (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1) (1 (2 (333 (444) 3 (4 (5) 4) 3) 2) 1)
with
species_str ( id, name) as (
select 100, 'CfwHE3 (HH3d) Jt1 (CD-1)' from dual union all
select 101, '4GSdg-3t 22sfG/J (mdx (fq) KO)' from dual union all
select 102, 'Yf7mMjfel 7(tm1) (SCID)' from dual union all
select 103, 'B29fj;jfos x11 (tmos (line x11))' from dual union all
select 104, 'B29;CD (Atm (line G5))' from dual union all
select 105, 'Ifkso30 jel-3' from dual union all
select 106, '13GupSip (te3x) Blhas/J' from dual union all
select 151, '' from dual union all
select 152, 'try (this (and (this))) ok?' from dual union all
select 153, 'try (this (and (this)) ok?)' from dual union all
select 154, 'try (this (and) this (ok))?' from dual union all
select 155, 'try (this (and (this)' from dual union all
select 156, 'right grouping (includging ")")' from dual union all
select 157, 'try this out ) ( too' from dual
),
prep ( id, name, pos ) as (
select id, name, instr(name, ')', -1)
from species_str
),
rec ( id, name, str, len, prev_pos, new_pos, flag ) as (
select id, name, substr(name, 1, instr(name, ')', -1)),
pos, pos - 1, pos, null
from prep
union all
select id, name, str, len, new_pos,
instr(str, '(', -(len - new_pos + 2)),
case when length(replace(substr(str, new_pos), '(', '')) =
length(replace(substr(str, new_pos), ')', ''))
then 1 end
from rec
where prev_pos > 0 and flag is null
)
select id, name, case when flag = 1
then substr(name, prev_pos, len - prev_pos + 1) end as target
from rec
where flag = 1 or prev_pos <= 0 or name is null
order by id;
ID NAME TARGET
---------- -------------------------------- --------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J (te3x)
151
152 try (this (and (this))) ok? (this (and (this)))
153 try (this (and (this)) ok?) (this (and (this)) ok?)
154 try (this (and) this (ok))? (this (and) this (ok))
155 try (this (and (this) (this)
156 right grouping (includging ")")
157 try this out ) ( too
14 rows selected
在最外层的中选择(在代码底部),当flag=1时,我们有情况,然后…
要定义目标
列,请添加如下条件:
... , case when flag = 1 and len = length(name) then ...
此修改后的输出:
ID NAME TARGET
---------- -------------------------------- --------------------------------
100 CfwHE3 (HH3d) Jt1 (CD-1) (CD-1)
101 4GSdg-3t 22sfG/J (mdx (fq) KO) (mdx (fq) KO)
102 Yf7mMjfel 7(tm1) (SCID) (SCID)
103 B29fj;jfos x11 (tmos (line x11)) (tmos (line x11))
104 B29;CD (Atm (line G5)) (Atm (line G5))
105 Ifkso30 jel-3
106 13GupSip (te3x) Blhas/J
151
152 try (this (and (this))) ok?
153 try (this (and (this)) ok?) (this (and (this)) ok?)
154 try (this (and) this (ok))?
155 try (this (and (this) (this)
156 right grouping (includging ")")
157 try this out ) ( too
14 rows selected
Oracle正则表达式没有PCRE或.NET强大,因此,您只能使用预定义级别的嵌套。例如,如果只有1个嵌套括号,您可以使用。否则,您需要一些解析功能。@WiktorStribiżew因此,如果我在Oracle中有测试(get(me)(too))
,我将无法获得(get(me)(too))
?不,就像。你只是不能将任意递归子模式与Oracle正则表达式匹配。我提供的模式将使用1个嵌套级别,它可以增强为支持2个级别,并且比现在更不可读。@WiktorStribiżew我认为这很好。谢谢!经过一点努力,我找到了一个涵盖所有问题的解决方案可能的情况(我相信),不需要编写函数,根本不使用正则表达式,不需要任何解析功能,也不需要运行数百行。一般来说,最好不要对“不可能”的事情发表意见除非有人确切知道,否则这些声明可能会让其他人甚至不去尝试。因此,我尝试了你的正则表达式,但到目前为止,查询仍在运行:我的正则表达式更快,因为它遵循了展开循环的原则。此正则表达式包含一个替换项,将执行一点(或更多,取决于数据)慢一点。@WiktorStribiżew似乎是这样。我之前让查询运行了3分钟多