Oracle如何使用正则表达式将此字符串字段转换为结构化数据?

时间:2014-08-25 16:33:02

标签: regex oracle parsing

我确实从这个答案开始: Oracle 11g get all matched occurrences by a regular expression

但它并没有让我足够远。我有一个字符串字段,如下所示:

A =&安培; TOKEN1&安培; token2&安培; token3,B =&安培; token2&安培; token3&安培; token5

它可以有任意数量的令牌和任意数量的键。所需的输出是一组如下所示的行:

  钥匙|令牌

   A | &安培; TOKEN1
   A | &安培; token2
   A | &安培; token3
   B | &安培; token2
   B | &安培; token3
   B | &安培; token5

事实证明这很难做到。

我从这里开始:

SELECT token from 
  (SELECT REGEXP_SUBSTR(str, '[A-Z=&]+', 1, LEVEL) AS token
    FROM (SELECT 'A=&token1&token2&token3,B=&token2&token3&token5' str from dual)
  CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(str, '[A-Z=&]+', ',')))
  Where token is not null

但是这会产生:

A=&
&
&
B=&
&
&

这让我无处可去。我认为我需要做一个嵌套的聪明选择第一个让我的地方

A=&token1&token2&token3
B=&token2&token3&token5

随后的选择可能会做一个聪明的提取以获得最终结果。

难住了。我试图在不使用程序或函数代码的情况下尝试这样做 - 我希望这个集合能够与其他查询结合使用,所以如果可以使用嵌套选择来实现这一点,那将是很好的。

更新:

SET DEFINE OFF
SELECT SUBSTR(token,1,1) as Key, REGEXP_SUBSTR(token, '&\w+', 1, LEVEL) AS token2
FROM
(
-- 1 row per key/value pair
  SELECT token from 
  (SELECT REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL) AS token
    FROM (SELECT 'A=&token1&token2&token3,B=&token2&token3&token5' str from dual)
  CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(str, '[^,]+', ',')))
  Where token is not null
)
CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(token, '&\w+'))

这让我

A | &安培; TOKEN1
A | &安培; token2
B | &安培; token3
B | &安培; token2
A | &安培; token2
B | &安培; token3

除了小问题(A应该有一个令牌3,令牌4和令牌5无处可见)之外,哪种格式很棒?

1 个答案:

答案 0 :(得分:0)

好问题!谢谢你!

select distinct k, regexp_substr(v, '[^&]+', 1, level) t
from (    
  select substr(regexp_substr(val,'^[^=]+=&'),1,length(regexp_substr(val,'^[^=]+=&'))-2) k, substr(regexp_substr(val,'=&.*'),3) v
  from (
    select regexp_substr(str, '[^,]+', 1, level) val
    from (select 'A=&token1&token2&token3,B=&token2&token3&token5' str from dual)
    connect by level <= length(str) - length(replace(str,','))+1
  )
) connect by level <= length(v) - length(replace(v,'&'))+1

这是一个答案,似乎有效......但我不喜欢将val分成kv的中间 - 必须有一个更好的方式(如果Key总是一个字符,那么它很容易)。并且不得不放一个DISTINCT来摆脱重复......很可能在进一步玩你可以清理它(或其他人可能)

编辑基于保持领先优势而关键是一个字符:

select distinct k, regexp_substr(v, '&[^&]+', 1, level) t
from (    
  select substr(val,1,1) k 
  , substr(regexp_substr(val,'=&.*'),1) v
  from (
    select regexp_substr(str, '[^,]+', 1, level) val
    from (select 'A=&token1&token2&token3,B=&token2&token3&token5' str from dual)
    connect by level <= length(str) - length(replace(str,','))+1
  )
) connect by level < length(v) - length(replace(v,'&'))+1