正则表达式从列表中选择第 n 个值,允许空值

Posted

技术标签:

【中文标题】正则表达式从列表中选择第 n 个值,允许空值【英文标题】:REGEX to select nth value from a list, allowing for nulls 【发布时间】:2014-10-28 05:02:18 【问题描述】:

我正在使用REGEXP_SUBSTR() 从逗号分隔列表中返回第 n 个值。当所有值都存在时,这工作正常,但如果项目为空,则失败。这是一个适用于所有值都存在的示例,并且我选择了第二次出现的 1 个或多个非逗号字符:

SQL> select REGEXP_SUBSTR('1,2,3,4,5,6', '[^,]+', 1, 2) data
  2  from dual;

D
-
2

但是当第二个值为空时,我真的得到了列表中的第三个项目,这当然是第二次出现 1 个或多个不是逗号的字符。但是,我需要它返回 NULL,因为第二项是空的:

SQL> select REGEXP_SUBSTR('1,,3,4,5,6', '[^,]+', 1, 2) data
  2  from dual;

D
-
3

如果我将正则表达式更改为允许零个或多个字符而不是 1 个或多个字符,那么对于超过 null 的数字也会失败:

SQL> select REGEXP_SUBSTR('1,,3,4,5,6', '[^,]*', 1, 4) data
  2  from dual;

D
-
3

我需要允许 null 但似乎无法正确使用语法。从逻辑上讲,无论数据是否存在,我都需要返回第 n 次出现逗号之前的内容(并允许最后一个值)。有什么想法吗?

【问题讨论】:

这是重复的。解析带有空值的 csv 字符串是一个常见问题(例如***.com/questions/25529511/…)。我偏爱我的解决方案(在字符串前面加一个逗号,并让你的正则表达式模式为 ',[^,]*'。接下来,LTRIM 匹配的 regexp_substr。 【参考方案1】:

感谢回复的人。在仔细阅读您的答案和提供的链接中的答案后,我得出了这个解决方案:

SQL> select REGEXP_SUBSTR('1,,3,4,5', '(.*?)(,|$)', 1, 2, NULL, 1) data
  2  from dual;

Data
----

这可以描述为“查看第二次出现的零个或多个可选字符集,后跟逗号或行尾,并返回第一个子组(即数据减去逗号或行尾)。

我忘了说我在不同位置测试了空值,多个空值,选择不同位置等。

我能找到的唯一警告是,如果您查找的字段大于可用的数字,它只会返回 NULL,因此您需要注意这一点。对我来说不是问题。

编辑:为了将来可能偶然发现此问题的搜索者的利益,我正在更新已接受的答案。

下一步是封装代码,以便将其制成更简单、可重用的函数。函数源码如下:

  FUNCTION  GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
    BEGIN
      RETURN REGEXP_SUBSTR(string_in, '(.*?)(\'||delimiter_in||'|$)', 1, element_in, NULL, 1);
  END GET_LIST_ELEMENT;

这对可能不太适应它的开发人员隐藏了正则表达式的复杂性,并使代码在使用时更清晰。像这样调用它以获得第 4 个元素:

select get_list_element('123,222,,432,555', 4) from dual;

【讨论】:

我确实喜欢使用交替运算符和使用字符组以及传递子表达式的能力(例如,1 作为第一个子表达式)。我在 11g 中没有意识到这个添加的功能。 @Aramillo - 谢谢!今天有趣的学习经历。帕特里克——直到我阅读了你指给我的那篇文章,并在指定 11g 时重新搜索了 REGEXP_SUBSTR 的手册页,我才知道。所以,谢谢!【参考方案2】:

像这样残酷的事情怎么样:

select REGEXP_SUBSTR(replace('1,,3,4,5,6', ',,', ',NULL,'), '[^,]+', 1, 2) data
from dual

返回字符串值。您可以使用案例获得真实的NULL

select (case when REGEXP_SUBSTR(replace('1,,3,4,5,6', ',,', ',NULL,'), '[^,]+', 1, 2) = 'NULL'
             then NULL
             else REGEXP_SUBSTR(replace('1,,3,4,5,6', ',,', ',NULL,'), '[^,]+', 1, 2)
        end)
from dual;

可能有一个仅限regexp_ 的解决方案,但这是首先想到的。

【讨论】:

确实很残酷 :) 可能工作正常,直到您尝试加载包含 NULL 作为文本的数据,并且您希望保持这种状态。虽然不是一个坏主意......

以上是关于正则表达式从列表中选择第 n 个值,允许空值的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式 - 如何从列表中选择第一项

正则表达式如何匹配空值?

正则表达式如何匹配空值?

正则表达式从头到尾匹配

从 URL 列表中选择文件路径的正则表达式

列表从另一个列表中选择正则表达式