PL/SQL Разделить строку по шаблону

Аналогично этому вопросу...

Как можно Я использую регулярное выражение для разделения строки, используя строку в качестве разделителя?

... Я пытаюсь разбить следующую строку:

Spent 30 CAD in movie tickets at Cineplex on 2018-06-01

Мой желаемый результат таков:

ELEMENT ELEMENT_VALUE
------- -------------
      1 Spent
      2 30
      3 CAD
      4 movie tickets
      5 Cineplex
      6 2018-06-01

Точно так же он должен иметь возможность обрабатывать:

Paid 600 EUR to Electric Company

Производство:

ELEMENT ELEMENT_VALUE
------- -------------
      1 Paid
      2 600
      3 EUR
      4 
      5 Electric Company

Я пробовал это регулярное выражение безрезультатно:

(\w+)(\D+)(\w+)(?(?=in)(\w+)(at)(\w+)(on)(.?$)|((?=to)(\w+)(.?$)))

Я просмотрел пару веб-сайтов с регулярными выражениями, а также этот пост без особой удачи:

Извлеките часть текста, разделенную разделителем, используя регулярное выражение

Может ли кто-нибудь помочь?


person Jaquio    schedule 31.05.2018    source источник
comment
Oracle не поддерживает группы без захвата или упреждающий просмотр в регулярных выражениях.   -  person MT0    schedule 01.06.2018


Ответы (2)


Вот простой токенизатор SQL, который разбивается на пробел:

select regexp_substr('Spent 30 CAD in movie tickets at Cineplex on 2018-06-01','[^ ]+', 1, level) from dual
connect by regexp_substr('Spent 30 CAD in movie tickets at Cineplex on 2018-06-01', '[^ ]+', 1, level) is not null

From: https://blogs.oracle.com/aramamoo/how-to-split-comma-separated-string-and-pass-to-in-clause-of-select-statement

person eaolson    schedule 31.05.2018

Есть две проблемы с требуемым результатом. Во-первых, как определить токены, которые вы хотите исключить («на», «на» и т. д.). Во-вторых, как игнорировать пробелы в некоторых токенах («Электрическая компания», «билеты в кино»).

Достаточно легко решить пункт один с помощью двухэтапного процесса. Шаг №1 разбивает строку на пробелы, шаг №2 удаляет ненужные токены:

with exclude as (
  select 'in' as tkn from dual union all
  select 'at' as tkn from dual union all
  select 'to' as tkn from dual union all
  select 'on' as tkn from dual 
  )
  , str as (
    select id
           , level as element_order
           , regexp_substr(txt, '[^ ]+', 1, level) as tkn
    from t23
    where id = 10
    CONNECT BY level <= regexp_count(txt, '[^ ]+')+1
    and id = prior id
    and prior sys_guid() is not null
    )
 select row_number() over (partition by str.id order by str.element_order) as element
       , str.tkn as element_value
 from str
      left join exclude on exclude.tkn = str.tkn
 where exclude.tkn is null
 and str.tkn is not null
 ;

Вот демонстрация SQL Fiddle.

Второй момент довольно сложно решить. Я предполагаю, что вам понадобится другая справочная таблица, чтобы идентифицировать звонки, и, возможно, использовать listagg() для их конкатенации.

person APC    schedule 01.06.2018