我试图从管道分隔文本中提取不同的值。当我在谷歌搜索时,我得到了以下表达,但在某些情况下它不起作用
EG:
select regexp_replace('Bhal|Bhal|Bhal|Bhaloo|Bhaloo|Bhaloo|Bhaloooo|Bhaloooo|Bhaloooo|Baker|Baker|Baker', '([^|]+)(\|\1)+', '\1') from dual;
预期产出:
Bhal | Bhaloo | Bhaloooo |贝克
我在正则表达式中尝试了一些组合,但它对我不起作用。
任何帮助都将不胜感激。
答案 0 :(得分:1)
这肯定是一个挑战。首先要了解为什么原件失败了。找到'Bhal'
的第一个字符串也是第二个字符串'Bhaloo'
的第一部分。因此,字符串的一部分与'([^|]+)(\|\1)+'
的原始正则表达式相匹配(读作:匹配一组一个或多个不是管道的字符,后跟一个或多个由管道组成的组,后面跟着记住的字符串)第一组)包括第一次出现Bhaloo
的前4个字符,导致正则表达式引擎在处理时使用字符串中的那些字符。对于发现的其余模式也是如此。关键是要包括结束模式,如果正则表达式引擎位于字符串的末尾,它将是结束管道或行尾字符。在这里,我添加了(\||$)
的结束模式组,其中显示为'其后是管道或行的末尾'。这可以确保如果字符串碰巧匹配下一个字符串的开头,则它将不会被正则表达式引擎使用。然后替换模式将结束字符串添加为\3
以确保它在输出中打印(基本上将其添加回来,因为它通过检查来消耗它)。
SQL> select regexp_replace('ABhal|Bhal|Bhal|Bhal|Bhaloo|Bhaloo|Bhaloo|Bhaloooo|Bhaloooo|Bhaloooo|||||Baker|Baker|Baker',
2 '([^|]*)(\|\1)*(\||$)', '\1\3') as unique_values
3 from dual;
UNIQUE_VALUES
---------------------------------
ABhal|Bhal|Bhaloo|Bhaloooo||Baker
SQL>
编辑:轻微调整在其他值之间处理NULLS。不确定这是多么有用。改变了测试用例。还将正则表达式更改为匹配零或更多而不是一个或多个(星号而不是加号)。
注意事项:
我接受了自己的建议,并测试了意想不到的值。总是期待意外!也许这些可能是你的因素?
这要求列表已经按顺序排列。即如果还有另一个' Bhal'最后,它将被视为一个新值。
Null也不会优雅地处理。好吧,有点。更改了上面的测试用例来说明。
答案 1 :(得分:0)
我不得不添加一个|在字符串的末尾,使它工作,所以它不是最优雅的解决方案,但我相信它的工作原理:
select rtrim(regexp_replace('Bhal|Bhal|Bhal|Bhaloo|Bhaloo|Bhaloo|Bhaloooo|Bhaloooo|Baker|Baker|Baker'||'|'
, '([^|]+\|)(\1)+', '\1'),'|')from dual
答案 2 :(得分:0)
我认为问题在于它只是在寻找:
(非管道字符串)(管道符)(在\ 1处找到的字符串)
在abc|abcd
的情况下将是部分匹配。
这几乎有效:
select regexp_replace(
'Bhal|Bhal|Bhal|Bhaloo|Bhaloo|Bhaloo|Bhaloooo|Bhaloooo|Bhaloooo|Baker|Baker|Baker'
, '([^|]+)(\|)(\1\|)+'
, '\1|' )
from dual;
虽然它没有抓住最后的Baker
,因为它没有跟随管道。如果你不介意再将一个管道字符连接到源字符串的末尾并清理输出,那么就在那里。
答案 3 :(得分:0)
问题已经得到很好的识别,并通过其他答案进行分析。所以我只是在这里添加另一种可能的解决方案 至少,对于问题中给出的测试用例,这会产生预期的输出。
select regexp_replace('Bhal|Bhal|Bhal|Bhaloo|Bhaloo|Bhaloo|Bhaloooo|Bhaloooo|Bhaloooo|Baker|Baker|Baker', '(.+?)(\|)((\1(\2|$))+)', '\1\5') from dual
简要说明: 请注意,Capture组由组开头的左括号编号。
( ) ( ) ( ( ( ) ) )
1 2 3 4 5
此处,组5包含在组4中,组4又包含在组3中。
捕获组1 - > (。+?)匹配一个或多个字符。 这是非贪婪的,所以当正则表达式的下一部分匹配时停止。
The expression given in the question [^|]+ works as well.
This effectively matches one of the words in the string.
捕获组2 - > (\ |)匹配分隔符,这是一个文字' |'
捕获组3 - > ((\ 1(\ 2 | $))+) 这包含组4,组4又包含组5.这匹配了一个"序列中的一个单词后面跟着一个分隔符或字符串的结尾"
捕获组4 - > (\ 1(\ 2 | $)) 实际的单词在第1组中匹配,后跟分隔符 (这是第2组)或字符串的结尾
捕获组5 - > (\ 2 | $) 匹配分隔符' |'或者字符串的结尾
答案 4 :(得分:0)
我结合了一些想法,现在使用一个函数返回一个字符串中唯一值的不同排序列表。此方法不要求列表已按其他答案进行排序。
这个SQL也可以在子选择而不是函数中使用。
function UniqueList (cList varchar2, cNewItem varchar2 default '', cDelim varchar2 default ',')
return varchar2
is
cResult varchar2(4000);
begin
select distinct listagg(txt,cDelim) WITHIN GROUP (ORDER BY txt) OVER () into cResult
from (
select distinct * from (
SELECT REGEXP_SUBSTR (cList||cDelim||cNewItem,'[^'||cDelim||']+',1,LEVEL) TXT
FROM DUAL
CONNECT BY REGEXP_SUBSTR (cList||cDelim||cNewItem,'[^'||cDelim||']+',1,LEVEL)
IS NOT NULL
)
);
return cResult;
end;