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

How to get all combinations (ordered sampling without replacement) in regex

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

(我认为这是一种没有放回的有序抽样的情况)
以 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 进行测试。

旁注:

编辑:澄清了正例列表

我不会为此使用正则表达式,例如要求 "have to be unique" 和 "have to be in ascending order" 不能真正用正则表达式表达(至少我想不出一种方法来做到这一点)。

由于您还需要有一个在 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;

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

然后使用以下示例数据:

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;

会 return:

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[=14= 中的布尔数据类型]


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