Как получить все комбинации (заказанная выборка без замены) в регулярном выражении - PullRequest
0 голосов
/ 11 марта 2019

Я пытаюсь сопоставить строку чисел через запятую с определенным шаблоном в запросе sql. В прошлом я успешно использовал регулярные выражения для подобных проблем, поэтому я пытаюсь заставить их работать и здесь. Проблема заключается в следующем:

  • Строка может содержать любое число в диапазоне (например, 1-4) ровно 0-1 раз.
  • Два числа разделены запятыми
  • Числа должны быть в порядке возрастания

(мне кажется, это своего рода случай упорядоченной выборки без замены)
Придерживаясь примера 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 уже возможен, можно подумать о больших диапазонах.

Я использовал регулярное выражение для целей тестирования.

Примечания:

  • Поскольку я использую sql, можно было бы реализовать некоторый алгоритм на другом языке, чтобы сгенерировать все возможные комбинации и сохранить их в таблице, которую можно использовать для объединения, см., Например. Как получить все возможные комбинации элементов списка? . Я хотел бы только полагаться на это в качестве крайней меры, поскольку создание новых таблиц будет связано с большим количеством записей.
  • Результирующий SQL-оператор, использующий регулярное выражение, должен выполняться как в Postgres, так и в Oracle.
  • Множество положительных примеров также называют «powerset».

Редактировать: Уточнил список положительных примеров

1 Ответ

2 голосов
/ 11 марта 2019

Я бы не использовал Regex для этого, так как, например, требования «должны быть уникальными» и «должны быть в порядке возрастания» не могут быть выражены с помощью регулярного выражения (по крайней мере, я не могу придуматьспособ сделать это).

Поскольку вам также необходимо иметь выражение, идентичное в Postgres и Oracle, я бы создал функцию, которая проверяет такой список, а затем скрывает конкретную реализацию СУБД в этой функции.

Для 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, вам, вероятно, понадобитсяиспользовать returns integer в Postgres, поскольку Oracle по-прежнему не поддерживает логический тип данных в SQL


Функции обработки строк в Oracle менее мощные, чем функции Postgres (например, без string_to_array или unnest), но вывозможно, может реализовать аналогичную логику в PL / SQL (хотя и более сложную)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...