【问题标题】:Regex in oracleoracle中的正则表达式
【发布时间】:2019-06-19 14:39:28
【问题描述】:

如何在 Oracle 中使用 REGEXP_SUBSTR

获取我想要的这些数据
SPRINTMVNO_PM_CDR_IWIRELESS_20121110_0813.csv get '08'in last four digits
RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt  get '0043722' in the middle(between'_')
wireless_201211120015_201211120515            get '0515' (last four digits)

我尝试了很多次,但有些表达式在 PHP 或其他语言中可以正常工作,但在 ORACLE 中不能正常工作。也许语法不同。

例如:第二个我可以使用/(?<=_)[0-9]*(?=_)/ 来获取 php 中的数字,但这在 Oracle 中不起作用。
我试过了

SELECT REGEXP_SUBSTR('RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt','(?<=_)[0-9]*(?=_)') 
  FROM dual;

没有输出。所以不是两条斜线的问题

这个问题的另一种表述是“如何使用 Oracle 的正则表达式在字符之间获取内容或以字符开头但不包含?”

我知道我可以通过使用字符串函数轻松获取这些数据,问题是要处理大量不同的字符串,每个字符串都有不同的数据要检索。所以我想将模式存储到数据库中,并使用一个 regexp_substr 来获取所有数据。否则我需要对这些规则进行硬编码。

【问题讨论】:

  • 您能解释一下您要应用的规则吗?您呈现三个字符串,每个字符串都有不同的输出。大概你想要三种不同的搜索模式。
  • 您的问题似乎是,当这些字符串的大小、位置和含义完全随机时,如何从正则表达式中获取非随机字符串。?
  • @APC 是的,我想要三种不同的模式来从这三个字符串中找到特定的数据。对于我需要搜索的每个示例,都会有更多类似的字符串。 For example: RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt this string may have other similar ones like RK_IPDR_RKMSG2_0043724_DT_20121113162712.txt ;RK_IPDR_RKMSG2_0043725_DT_20121113162711.txt the different part is what I want to get, which is the 7 digits number for this example, but the length may change
  • @Ben 很抱歉让您感到困惑,这是三组不同的字符串。
  • 您的用例是什么?你得到一个随机字符串并应用所有这些模式来查看哪个匹配?你得到一堆字符串并只应用一个模式来查看哪个匹配?还是其他一些排列?您在一次搜索中处理什么样的数据量?另外,什么版本的数据库?

标签: regex oracle string-matching


【解决方案1】:

Oracle 实践者在没有正则表达式的情况下存活了多年,因为 Oracle 提供了一些简单的字符串函数,我们可以将它们组合起来进行一些漂亮的操作。

例如,要查找字符串中最后一个下划线之后的前两个字符,请使用 SUBSTR() 和 INSTR(),如下所示:

with t as (select 'SPRINTMVNO_PM_CDR_IWIRELESS_20121110_0813.csv' str from dual)
select substr(str, instr(str, '_', -1)+1, 2)
from t
/

注意 INSTR() 调用有一个负偏移量,从后面开始计数。获取字符串的最后四个字符使用相同的技巧:

with t as (select 'iwireless_201211120015_201211120515' str from dual)
select substr(str, -4)
from t
/

识别 下划线后跟数字后跟下划线的模式的最简单方法是使用正则表达式,但我们可以使用 TRIM() 从结果中删除下划线。

with t as (select 'RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt' str from dual)
select trim('_' from regexp_substr(str, '_([0-9]+)_'))
from t
/

这里是a SQL Fiddle,以证明这些技术有效。

Oracle 有大量的函数,这些函数在文档中进行了描述。 Find out more.


" 请忽略这些情况,我只需要一个解决方案'如何获得 内容之间或以字符开头但不包括它,与 Oracle 的正则表达式?'"

有一种方法可以从结果的开头或结尾排除字符,即将搜索模式分解为子表达式。这将适用于您提供的字符串,因为我们可以将前导和尾随下划线与所需数字分开。不幸的是,subexpressions 参数是the last parameter in the REGEXP_SUBSTR() signature,并且由于 SQL 函数不接受命名参数,这意味着我们必须显式传递所有其他参数的默认值。

无论如何,此调用将返回第二个子表达式,即所需的字符串0043722

with t as (select 'RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt' str from dual)
select regexp_substr(str, '(_)([0-9]+)(_)', 1,1,'i',2)
from t
/

用例确实很重要。 REGEXP 函数的执行速度比更简单的等效函数慢。在 10gR2 中,REGEXP_SUBSTR() 至少比 SUBSTR() 慢一个数量级。当搜索大量字符串时,差异很明显,当这个数字变成数百万时,差异就很明显了(披露:最近的痛苦)。

【讨论】:

  • 我知道我可以通过使用字符串函数轻松获取这些数据,问题是有大量不同的字符串要处理,每个字符串都有不同的数据要检索,所以我想将模式存储到数据库,并使用一个 regexp_substr 来获取所有数据。否则我需要对这些规则进行硬编码,这不是一个好的解决方案。
  • 你很有耐心,伙计。感谢您的解决方案。 trim('' from regexp_substr(str, '_([0-9]+)')) 这启发了我,我只需要在我的代码中添加这个修剪函数来转义所有'_'
【解决方案2】:

正则表达式前后的斜线与正则表达式无关

它们是 perl/javascript 语言的产物。

试试没有斜线

【讨论】:

  • 我试过 SELECT REGEXP_SUBSTR('RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt','(?
【解决方案3】:

Oracle 使用 POSIX ERE(扩展正则表达式) - 一个显着的例外是它添加了反向引用。但是 POSIX ERE 非常有限——它只需要很少的东西。试试下面的正则表达式:

/([0-9]{2}80|[0-9]80[0-9]|80[0-9]{2})$/

最后四位数为 80。

/0515$/

最后四位数为 0515。

现在,我从未使用过 Oracle,所以我不知道您是否需要分隔符,但这两个会起作用。中间的有点棘手。如果您可以只接受“是的,它就在那里”,那么您应该可以摆脱

/_0043722_/

但是如果您需要提取它,您应该能够找到一些修剪功能,让您指定要修剪的内容。你不能在 Oracle 中使用正则表达式。

哦,如果您需要将所有这三个组合成一个正则表达式:

/([0-9]{2}80|[0-9]80[0-9]|80[0-9]{2}|0515)$|_0043722_/

如果您将来需要正则表达式参考,请尝试this site

【讨论】:

  • 这些字符串只是示例,数字是动态生成的,我想将它们提取出来。无论如何感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-19
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 2017-05-13
  • 1970-01-01
相关资源
最近更新 更多