如何在正则表达式中获取所有组合(有序抽样,无需替换)

时间:2019-03-11 09:50:18

标签: sql regex combinatorics

我正在尝试将逗号分隔的数字字符串与sql查询中的特定模式匹配。过去,我成功地使用正则表达式解决了类似的问题,因此,我也试图使其在这里也能正常工作。问题如下:

  • 字符串可以包含0-1范围内的任意数字(例如1-4)。
  • 两个数字以逗号分隔
  • 数字必须按升序排列

(我认为这是一种有序采样而无替换的情况)
坚持1-4的示例,以下条目应匹配:

1 
1,2 
1,3 
1,4 
1,2,3 
1,2,4 
1,3,4 
1,2,3,4
2 
2,3 
2,4 
3 
3,4
4

而这些不应:

q dawda 323123 a3 a1 1aa,1234 4321 a4,32,1a 1112222334411 
1,,2,33,444, 11,12,a  234 2,2,3 33 3,3,3 3,34 34 123 1,4,4,4a 1,444 

我目前最好的尝试是:

\b[1-4][\,]?[2-4]?[\,]?[3-4]?[\,]?[4]?\b

这仍然有两个主要缺点:

  1. 它会带来很多误报。数字一旦出现就不会消除。
  2. 当数字范围增加时,它将变得相当长,例如1-18也已经可能,可以考虑更大的射程。

我使用regexpal进行测试。

旁注:

  • 当我使用sql时,可以用另一种语言实现某种算法来生成所有可能的组合,并将它们保存在可用于联接的表中,例如How to get all possible combinations of a list’s elements?。我只想依靠它作为最后的手段,因为将涉及创建新表,并且这些表将包含很多条目。
  • 使用正则表达式的结果sql语句应同时在Postgres和Oracle上运行。
  • 一组积极的例子也称为“ powerset”。

编辑:澄清了正面示例列表

1 个答案:

答案 0 :(得分:2)

我不会为此使用正则表达式,例如要求“必须是唯一的”和“必须以升序”不能真正用正则表达式表示(至少我想不到做到这一点的方法)。

由于您还需要在Postgres和Oracle中具有相同的表达式,因此我将创建一个检查此类列表的函数,然后在该函数中隐藏特定于DBMS的实现。

对于Postgres,我将使用其数组处理功能来实现该功能:

create or replace function is_valid(p_input text)
  returns boolean
as
$$
  select coalesce(array_agg(x order by x) = string_to_array(p_input, ','), false)
  from (
    select distinct x
    from unnest(string_to_array(p_input,',')) as t(x)
    where x ~ '^[0-9]+$' -- only numbers
  ) t
  where x::int between 1 and 4 -- the cast is safe as the inner query only returns valid numbers
$$
language sql;

内部查询以单个数字的形式返回输入列表中的所有(不同的)元素。然后,外部查询聚合返回所需范围和数字顺序的值。如果该结果与输入的结果不同,则该输入无效。

然后显示以下示例数据:

with sample_data (input) as (
  values 
    ('1'),
    ('1,2'),
    ('1,3'), 
    ('1,4'), 
    ('1,2,3'), 
    ('1,2,4'),
    ('foo'),
    ('1aa,1234'),
    ('1,,2,33,444,')
)
select input, is_valid(input)
from sample_data;

它将返回:

input        | is_valid
-------------+---------
1            | true    
1,2          | true    
1,3          | true    
1,4          | true    
1,2,3        | true    
1,2,4        | true    
foo          | false   
1aa,1234     | false   
1,,2,33,444, | false   

如果要在Postgres和Oracle中使用相同的功能,则可能需要在Postgres中使用returns integer,因为Oracle在SQL中仍然不支持布尔数据类型。


Oracle的字符串处理功能不如Postgres的功能强大(例如,没有string_to_array或unnest),但是您也可以在PL / SQL中实现类似的逻辑(尽管更复杂)