如何在第n次出现管道后得到字符或字符串' |'使用REGULAR_EXPRESSION在ORACLE中的符号?

时间:2017-07-23 15:55:10

标签: oracle plsql

在ORACLE中第n次出现管道|符号后,获取字符或字符串的正则表达式查询是什么?例如,我有两个字符串,如下所示,

 Jack|Sparrow|17-09-16|DY7009|Address at some where|details       
 |Jack|Sparrow|17-09-16||Address at some where|details

我想要' DY7009'在第3个管道符号从第1个位置开始之后,那么正则表达式查询是什么?并且在第二个字符串中假设第一个位置具有|符号,那么如果没有值,我想要第四个字符串,那么它应该给出NULL或BLANK值。

select regexp_substr('Jack|Sparrow|17-09-16|DY7009|Address at some where|details'
        ,' ?? --REX Exp-- ?? ') as col 
from dual;

结果 - DY7009

select regexp_substr('Jack|Sparrow|17-09-16|DY7009|Address at some where|details'
         ,' ?? --REX Exp-- ?? ') as col 
 from dual;

结果 - ''或(即NULL)

那么正则表达式应该是什么?请帮忙。提前谢谢

NEW UPDATE Edit ---

谢谢大家!!,谢谢你的回答!!我想,我没有问问题。我只想要一个正则表达式来获得'字符串/字符串'在第n次出现管道符号后。我不想替换任何字符串,所以只有regexp_substr才能完成这项工作。

---->如果'杰克|麻雀| SQY778 | 17JULY17 || 00J1'是一个字符串

我想在第二个管线符号后面找到字符串值,答案是SQY778。如果我想在第3个管道符号后找到字符串,那么答案将是17JULY17。如果我想在第4个管道符号之后找到值,那么它应该给出BLANK或NULL值,因为在第4个管道符号之后没有任何内容。如果我想找到字符串第5个符号,那么我只会替换正则表达式中的一个数字,即5,因此我将获得00J1。

4 个答案:

答案 0 :(得分:3)

你去吧。将regexp_substr()的第四个参数替换为所需字段的编号。

with tbl(str) as (
  select 'Jack|Sparrow|17-09-16|DY7009|Address at some where|details ' from dual
)
select regexp_substr(str, '(.*?)(\||$)', 1, 4, NULL, 1) field_4
from tbl;

FIELD_4
--------

DY7009

SQL>

列出所有字段:

with tbl(str) as (
  select 'Jack|Sparrow|17-09-16|DY7009|Address at some where|details ' from dual
)
select regexp_substr(str, '(.*?)(\||$)', 1, level, NULL, 1) split
from tbl
connect by level <= regexp_count(str, '\|')+1;

SPLIT
-------------------------

Jack
Sparrow
17-09-16
DY7009
Address at some where
details

6 rows selected.

SQL>

因此,如果您想要使用选择字段:

with tbl(str) as (
      select 'Jack|Sparrow|17-09-16|DY7009|Address at some where|details ' from dual
    )
    select 
      regexp_substr(str, '(.*?)(\||$)', 1, 1, NULL, 1) first,
      regexp_substr(str, '(.*?)(\||$)', 1, 2, NULL, 1) second,
      regexp_substr(str, '(.*?)(\||$)', 1, 3, NULL, 1) third,
      regexp_substr(str, '(.*?)(\||$)', 1, 4, NULL, 1) fourth
    from tbl;

请注意,此正则表达式处理NULL元素,仍将返回正确的值。其他一些答案使用'[^|]+'形式来解析字符串,但是当存在NULL元素时应该避免这种情况。请参阅此处以获取证明:https://stackoverflow.com/a/31464699/2543416

答案 1 :(得分:0)

您可以使用regex_replace获取第n个匹配组。在您的示例中,可以像这样检索第四个匹配:

select regexp_replace(
    'Jack|Sparrow|17-09-16|DY7009|Address at some where|details',
    '^([^\|]*\|){3}([^\|]*)\|.*$',
    '\4'
) as col
from dual;

编辑:感谢Arijit Kanrar指出丢失的转义字符。

要OP:regex_replace不会替换数据库中的任何内容,只能返回返回的字符串。

答案 2 :(得分:0)

您可以使用此查询获取特定列(第n次出现)的值,如下所示

SELECT nth_string
FROM
  (SELECT TRIM (REGEXP_SUBSTR (long_string, '[^|]+', 1, ROWNUM) ) nth_string ,
    level AS lvl
  FROM
    (SELECT REPLACE('Jack|Sparrow|17-09-16|DY7009|Address at some where|details','||','| |') long_string
    FROM DUAL
    )
    CONNECT BY LEVEL <= REGEXP_COUNT ( long_string, '[^|]+')
  )
WHERE lvl = 4;

请注意,我在oracle中使用标准查询将分隔的字符串拆分为记录。要在第二种情况下处理分隔符之间的空白,我将用空格' '替换它。应用TRIM()函数后,空间将转换为NULL。

您可以通过替换查询末尾nth中的数字来获取任何lvl =条记录。

让我知道您的反馈意见。感谢。

编辑:

似乎无法使用纯regexp_substr(),因为无法在&#39; ||&#39;之间转换空白。到Oracle NULL。需要中间TRIM(),我正在添加replace以便更轻松。将有一些模式直接匹配此方案,但无法找到它们。

以下是第4次出现的所有情景。

WITH t
     AS (SELECT '|Jack|Sparrow|SQY778|17JULY17||00J1' long_string
         FROM   dual
         UNION ALL
         SELECT 'Jack|Sparrow|SQY778|17JULY17||00J1' long_string
         FROM   dual
         UNION ALL
         SELECT '||Jack|Sparrow|SQY778|17JULY17|00J1' long_string
         FROM   dual)
SELECT long_string,
       Trim (Regexp_substr (mod_string, '\|([^|]+)', 1, 4, NULL, 1)) nth_string
FROM   (SELECT long_string,
               Replace(long_string, '||', '| |') mod_string
        FROM   t)  ;

    LONG_STRING                             NTH_STRING
   ------------------------                -----------
    |Jack|Sparrow|SQY778|17JULY17||00J1     17JULY17
    Jack|Sparrow|SQY778|17JULY17||00J1      NULL 
    ||Jack|Sparrow|SQY778|17JULY17|00J1     SQY778

EDIT2 :最后一个模式给出了解决方案。谢谢Gary_W

要从字符串中获取nth,请使用:

WITH t
     AS (SELECT '|Jack|Sparrow|SQY778|17JULY17||00J1' long_string
         FROM   dual
         UNION ALL
         SELECT 'Jack|Sparrow|SQY778|17JULY17||00J1' long_string
         FROM   dual
         UNION ALL
         SELECT '||Jack|Sparrow|SQY778|17JULY17|00J1' long_string
         FROM   dual)
SELECT long_string,
       Trim (regexp_substr (long_string, '(.*?)(\||$)', 1, :n + 1, NULL, 1)) nth_string
       FROM t;

答案 3 :(得分:0)

没有足够的声誉来评论克里斯·约翰逊的答案,所以加上我自己的答案。 Chris有正确的方法使用反向引用但忘记逃避管道角色。 正则表达式将如下所示。

    WITH dat
     AS (SELECT 'Jack|Sparrow|17-09-16|DY7009|Address at some where|details' AS str,
                3 AS pos
         FROM   DUAL
         UNION
         SELECT ' |Jack|Sparrow|17-09-16||Address at some where|details' AS str,
                4 AS pos
         FROM   DUAL)
SELECT str,
       pos,
       REGEXP_REPLACE (str, '^([^\|]*\|){' || pos || '}([^\|]*)\|.*$', '\2')
          AS regex_result
FROM   dat;

我通过动态添加管道角色的位置来动态创建正则表达式。

结果如下所示。

|杰克|麻雀| 17-09-16 ||地址在某处|详情(4):

Jack | Sparrow | 17-09-16 | DY7009 |地址在某处|详情(3):DY7009