两个字符分隔符上 SQL 中的正则表达式子字符串
Regular Expression Substring in SQL on two character delimeter
我正在尝试使用定界字符串和 return 定界符之间的每个子字符串。这用于我正在编写的更大的函数中,因此分隔符通常是一个变量。
我们使用的一个非常常见的分隔符是“,”,因此这是我的第一个测试用例。根据我如何格式化正则表达式中的定界符,我遇到了不同的问题。
以下是我尝试过的不同方法和结果:
select REGEXP_SUBSTR ('foo bar', '[^' || '(, )' || ']+', 1, LEVEL) item
from dual
connect by REGEXP_SUBSTR ('foo bar', '[^' || '(, )' || ']+', 1, LEVEL
select REGEXP_SUBSTR ('foo bar', '[^' || '(,\s)' || ']+', 1, LEVEL) item
from dual
connect by REGEXP_SUBSTR ('foo bar', '[^' || '(,\s)' || ']+', 1, LEVEL
select REGEXP_SUBSTR ('foo bar', '[^' || '(,[:blank:])' || ']+', 1, LEVEL) item
from dual
connect by REGEXP_SUBSTR ('foo bar', '[^' || '(,[:blank:])' || ']+', 1, LEVEL
第一次和第三次尝试在 space 上分隔 'foo' 和 'bar',即使没有逗号。后一种尝试将 'foo' 和 'bar' 保持在同一行,但如果字符串中有一个 s(例如 horse),结果是 'hor' 'e'。
我对正则表达式和regexp_substr的理解告诉我
'[^(,\s)]+'
应该在遇到逗号时分隔字符串,然后是白色space。但显然这不会发生。我还没有找到和我有类似问题的人。任何帮助将不胜感激
作为参考,我在 SQL Oracle Database 11g 企业版 11.2.0.4.0 版开发人员中工作 - 64 位生产
您对匹配字符列表的工作方式感到困惑。 From the documentation:
[char...] Matching Character List
Matches any single character in the list within the brackets. In the list, all > operators except these are treated as literals:
Range operator: -
POSIX character class: [: :]
POSIX collation element: [. .]
POSIX character equivalence class: [= =]
因此在您的模式中 '[^(,\s)]+'
每个字符都被视为文字; \
并没有使 s
被视为白色 space 字符,它只是一个 s
,因此它在 horse
中匹配。括号也是文字,因此它们不会在分隔符中包含这对字符,每个字符都与字符串中的实际括号匹配。在您的第一次和第三次尝试中,您仅在 space 上获得匹配,因为匹配列表中的每个字符都是独立的,它们不会像您期望的那样由括号组合。
据我所知,您不能否定一对值(尽管正则表达式不是强项,所以我很可能错了)。一种选择是用您知道不会出现的字符替换分隔符的所有外观 - 根据您的实际数据,您可能必须选择不可打印的字符或晦涩的 Unicode 字符 - 然后在正则表达式中使用它。
例如,为简洁起见使用绑定变量,并使用散列作为我知道不存在的字符:
variable string varchar2(20);
variable delimiter varchar2(2);
exec :string := 'foo bar, the cad, left';
exec :delimiter := ', ';
select regexp_substr(replace(:string, :delimiter, '#'),
'[^#]+', 1, level) as item
from dual
connect by regexp_substr(replace(:string, :delimiter, '#'),
'[^#]+', 1, level) is not null;
ITEM
--------------------
foo bar
the cad
left
您也可以这样做:
select trim(regexp_substr('foo bar, the cad, left','[^,]+',1,level)) from dual
connect by level <= regexp_count('foo bar, the cad, left',',')+1;
此查询搜索 ,
而不是 ,(space)
。但我认为你会得到相同的结果。如果您有 foo,bar, the cad, left
并且期望,这将不起作用
foo,bar
,the cad
,left
使用使用非贪婪量词的文本模式
遍历字符串以查找模式的多次出现,'(.+?)(, |$)'
:
模式(.+?)
是一个字符组。 .
指的是 any/all 个字符,+?
是 1 个或多个字符的非贪婪量词。
模式 (, |$)
查找 ', '
或(交替运算符,|
)字符串结尾的出现,$
.这是第二个字符组。
最后,使用子表达式只引用第一个字符组
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := 'foo,bar, great';
PL/SQL procedure successfully completed.
SCOTT@dev> SELECT regexp_substr(:tval,'(.+?)(, |$)', 1, LEVEL, NULL, 1) t_val
2 FROM dual
3 CONNECT BY regexp_substr(:tval,'(.+?)(, |$)', 1, LEVEL, NULL, 1) IS NOT NULL
4 /
T_VAL
--------
foo,bar
great
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := 'foo, bar, great';
PL/SQL procedure successfully completed.
SCOTT@dev> /
T_VAL
--------
foo
bar
great
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := 'foo,bar,great';
PL/SQL procedure successfully completed.
SCOTT@dev> /
T_VAL
--------
foo,bar,great
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := ',foo, bar, great';
PL/SQL procedure successfully completed.
SCOTT@dev> /
T_VAL
--------
,foo
bar
great
我正在尝试使用定界字符串和 return 定界符之间的每个子字符串。这用于我正在编写的更大的函数中,因此分隔符通常是一个变量。
我们使用的一个非常常见的分隔符是“,”,因此这是我的第一个测试用例。根据我如何格式化正则表达式中的定界符,我遇到了不同的问题。
以下是我尝试过的不同方法和结果:
select REGEXP_SUBSTR ('foo bar', '[^' || '(, )' || ']+', 1, LEVEL) item
from dual
connect by REGEXP_SUBSTR ('foo bar', '[^' || '(, )' || ']+', 1, LEVEL
select REGEXP_SUBSTR ('foo bar', '[^' || '(,\s)' || ']+', 1, LEVEL) item
from dual
connect by REGEXP_SUBSTR ('foo bar', '[^' || '(,\s)' || ']+', 1, LEVEL
select REGEXP_SUBSTR ('foo bar', '[^' || '(,[:blank:])' || ']+', 1, LEVEL) item
from dual
connect by REGEXP_SUBSTR ('foo bar', '[^' || '(,[:blank:])' || ']+', 1, LEVEL
第一次和第三次尝试在 space 上分隔 'foo' 和 'bar',即使没有逗号。后一种尝试将 'foo' 和 'bar' 保持在同一行,但如果字符串中有一个 s(例如 horse),结果是 'hor' 'e'。
我对正则表达式和regexp_substr的理解告诉我
'[^(,\s)]+'
应该在遇到逗号时分隔字符串,然后是白色space。但显然这不会发生。我还没有找到和我有类似问题的人。任何帮助将不胜感激
作为参考,我在 SQL Oracle Database 11g 企业版 11.2.0.4.0 版开发人员中工作 - 64 位生产
您对匹配字符列表的工作方式感到困惑。 From the documentation:
[char...] Matching Character List
Matches any single character in the list within the brackets. In the list, all > operators except these are treated as literals:
Range operator: -
POSIX character class: [: :]
POSIX collation element: [. .]
POSIX character equivalence class: [= =]
因此在您的模式中 '[^(,\s)]+'
每个字符都被视为文字; \
并没有使 s
被视为白色 space 字符,它只是一个 s
,因此它在 horse
中匹配。括号也是文字,因此它们不会在分隔符中包含这对字符,每个字符都与字符串中的实际括号匹配。在您的第一次和第三次尝试中,您仅在 space 上获得匹配,因为匹配列表中的每个字符都是独立的,它们不会像您期望的那样由括号组合。
据我所知,您不能否定一对值(尽管正则表达式不是强项,所以我很可能错了)。一种选择是用您知道不会出现的字符替换分隔符的所有外观 - 根据您的实际数据,您可能必须选择不可打印的字符或晦涩的 Unicode 字符 - 然后在正则表达式中使用它。
例如,为简洁起见使用绑定变量,并使用散列作为我知道不存在的字符:
variable string varchar2(20);
variable delimiter varchar2(2);
exec :string := 'foo bar, the cad, left';
exec :delimiter := ', ';
select regexp_substr(replace(:string, :delimiter, '#'),
'[^#]+', 1, level) as item
from dual
connect by regexp_substr(replace(:string, :delimiter, '#'),
'[^#]+', 1, level) is not null;
ITEM
--------------------
foo bar
the cad
left
您也可以这样做:
select trim(regexp_substr('foo bar, the cad, left','[^,]+',1,level)) from dual
connect by level <= regexp_count('foo bar, the cad, left',',')+1;
此查询搜索 ,
而不是 ,(space)
。但我认为你会得到相同的结果。如果您有 foo,bar, the cad, left
并且期望,这将不起作用
foo,bar
,the cad
,left
使用使用非贪婪量词的文本模式
遍历字符串以查找模式的多次出现,'(.+?)(, |$)'
:
模式
(.+?)
是一个字符组。.
指的是 any/all 个字符,+?
是 1 个或多个字符的非贪婪量词。模式
(, |$)
查找', '
或(交替运算符,|
)字符串结尾的出现,$
.这是第二个字符组。
最后,使用子表达式只引用第一个字符组
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := 'foo,bar, great';
PL/SQL procedure successfully completed.
SCOTT@dev> SELECT regexp_substr(:tval,'(.+?)(, |$)', 1, LEVEL, NULL, 1) t_val
2 FROM dual
3 CONNECT BY regexp_substr(:tval,'(.+?)(, |$)', 1, LEVEL, NULL, 1) IS NOT NULL
4 /
T_VAL
--------
foo,bar
great
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := 'foo, bar, great';
PL/SQL procedure successfully completed.
SCOTT@dev> /
T_VAL
--------
foo
bar
great
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := 'foo,bar,great';
PL/SQL procedure successfully completed.
SCOTT@dev> /
T_VAL
--------
foo,bar,great
SCOTT@dev> VAR tval VARCHAR2(500);
SCOTT@dev> EXECUTE :tval := ',foo, bar, great';
PL/SQL procedure successfully completed.
SCOTT@dev> /
T_VAL
--------
,foo
bar
great