Oracle SQL regexp_substr编号提取行为

ztyzrc3y  于 2023-05-06  发布在  Oracle
关注(0)|答案(2)|浏览(266)

在某种意义上,我已经回答了自己的问题,但我试图更好地理解答案:
当使用regexp_substr(在oracle中)提取一个数字的第一次出现(个位数或多位数)时,修饰符*+如何/为什么会影响结果?为什么+提供了我正在寻找的行为,而*没有?*是我在大多数正则表达式中的默认用法,所以我很惊讶它不适合我的需要。
例如,在以下中:

select test, 
regexp_substr(TEST,'\d') Pattern1,
regexp_substr(TEST,'\d*') Pattern2, 
regexp_substr(TEST,'\d+') Pattern3
from (
select '123 W' TEST from dual
union
select 'W 123' TEST from dual
);

regexp_substr(TEST,'\d*')的使用为输入“W 123”返回空值-因为字符串中存在“零个或多个”数字,我对这种行为感到困惑。我也很困惑为什么它在字符串'123 W'上有效
我的理解是,*意味着它后面的元素出现零次或多次,而+意味着前面的元素出现一次或多次。在为pattern 2 [\d*]提供的示例中,为什么它成功地从“123 W”中捕获“123”,但它没有从“W 123”中获取123,因为确实存在零个或多个数字,它们只是不存在于字符串的开头。使用*是否有附加的[隐含]逻辑?
注意:我找了一段时间,试图找到类似的问题,帮助我从'W 123'中捕获'123',但我发现最接近的是regexp_replace的变体,这不能满足我的需要。

ssm49v7z

ssm49v7z1#

因此,regexp_count表示有四个子字符串匹配\d* 模式。第三个是“123”。这意味着第一个和第二个是从W和空格中派生出来的,你得到的是一个零长度的结果,它“消耗”了源字符串的一个字符。

select test, 
    regexp_count(TEST,'\d*') Pattern2_c, 
    regexp_substr(TEST,'\d*') Pattern2,
    regexp_substr(TEST,'\d*',1,1) Pattern2_1,
    regexp_substr(TEST,'\d*',1,2) Pattern2_2,
    regexp_substr(TEST,'\d*',1,3) Pattern2_3,
    regexp_substr(TEST,'\d*',1,4) Pattern2_4
 from (select '123 W' TEST from dual
    union
    select 'W 123' TEST from dual
    );

Oracle有一个关于零长度字符串和null的奇怪事情。
结果并不“感觉”正确,但是如果你问一个计算机关于一个字符串中包含多少个零长度子串的深刻哲学问题,我不会打赌任何答案。

pzfprimi

pzfprimi2#

想一想,其实也有道理。模式\d*表示匹配任何数字或更多次。这里的问题是,字符串的开头将始终匹配此模式,因为有零次或多次。
如果字符串以数字开头,那么它将包括这些数字,因此给定123 W,模式匹配123。然而,给定模式W 123,该模式也在开始时匹配,但它匹配0个字符。这就是为什么你得到一个NULL结果。
这是一个通用的正则表达式的东西,而不是一个Oracle的东西。你必须小心使用*量词。
这里有两个正则表达式fiddle示例来说明这一点,使用字符串W 123

相关问题