Проверка диапазона дат в схеме BizTalk EDI

Мне нужно проверить диапазон дат в элементе в схеме BizTalk. Я получил даты с датами начала до даты окончания (20130521-20130501). Я знаю, что могу легко проанализировать и проверить эту строку с использованием XSLT и С# на карте, однако мне нужна проверка, чтобы быть частью схемы, чтобы, если транзакция с датой в этом формате получена, BizTalk отклонит транзакцию EDI и произвести отторжение 999 обратно отправителю.

Я прочитал множество сообщений, которые советуют не использовать проверку регулярных выражений для диапазонов дат, но помимо создания настраиваемого компонента конвейера или использования С#, я не вижу другого способа. Существует свойство схемы, которое позволяет использовать регулярные выражения для проверки входных данных.

Я не очень хорошо разбираюсь в регулярных выражениях и нуждаюсь в некоторой помощи, чтобы выяснить, как подтвердить, что дата начала меньше или равна дате окончания. Даты принимаются как строки. Я читал о разделении строк на "-", но не знаю, как сравнивать результаты. Любая помощь будет оценена.

Ответ 1

Отказ от ответственности: Я использую PHP, что означает, что я использую аромат PCRE regex.

Проблема

Кажется, что вы не знаете границ регулярных выражений, но это нормально.
На самом деле вопрос заключается в следующем: проверьте, соответствует ли x =< y.

Предел

Почему? Ну, вы хотите проверить, если start date =< end date. Идея регулярных выражений состоит в том, чтобы сопоставить определенные символы после определенного регулярного шаблона. Только в Regex не может проверить, есть ли x < y, поскольку регулярное выражение не имеет логических операторов > <.

Обход определенного предела

То, что regex может сделать, это проверить, есть ли x = y. Скажем, например, у меня есть следующая строка, и я хочу получить все строки, где x = y:

10 = 10
15 = 51
33 = 31
100 = 101
780 = 780

Мы можем использовать следующее регулярное выражение: ^(\d+)\s*=\s*\1$ с модификатором m. Что это значит?

  • ^: начало строки
  • (\d+): группировать и сопоставлять любую цифру один или несколько раз
  • \s*=\s*: совпадение пробелов 0 или более раз, а затем =, а затем любое пустое поле 0 или более раз
  • \1: ссылаясь на группу 1, поэтому сопоставляем, только если она такая же, как и в группе 1.
  • $: конец строки
  • m модификатор: многострочный. Сделайте ^ и $ совпадение начала и конца строки соответственно
    Онлайн-демонстрация.

Доказательство концепции

Позвольте взломать дальше. Для этого POC, мы будем соответствовать следующим: x-y где 0 =< x =< 9 и 0 =< y =< 9 и x =< y.
Мы можем попытаться сопоставить все возможности, где x =< y. Поэтому, если x=0 тогда y=[0-9], если x=1, то y=[1-9], если x=2, тогда y=[2-9] и т.д. Так как regex имеет оператор or, мы можем написать следующее регулярное выражение:
0-[0-9]|1-[1-9]|2-[2-9]|3-[3-9]|4-[4-9]|5-[5-9]|6-[6-9]|7-[7-9]|8-[8-9]|9-9
Онлайн-демонстрация
Ты видишь? Это на самом деле так долго для простого сравнения! Поэтому любой здравомыслящий человек будет анализировать и проверять его со встроенными языковыми инструментами.

Нарушение законов регулярного выражения

Мы будем использовать PHP для генерации выражения регулярного выражения:

$start = strtotime('2013-01-01'); // Start date
$end = strtotime('2013-03-01'); // End date
$range = array_map(function($v){return date('Ymd', $v);}, range($start, $end, 86400)); // Creating the range of dates
$result = ''; // Declaring an empty variable to store our regex in it

for($i=$start;$i<=$end;$i+=86400){ // loop each day
    $result .= '(?:' . date('Ymd', $i) . '-(?:'. implode('|', $range) . '))|'; // building our regex
    array_shift($range); // removing first element of range
}
$result = substr($result, 0, -1); // removing last | since we don't need it
echo $result; // Output

Вышеприведенный код будет генерировать регулярное выражение, которое может проверять дату между 2013-01-01 и 2013-03-01, где x =< y в форме x-y. Это регулярное выражение не оптимизировано и имеет значение 17 КБ. Итак, представьте размер этого регулярного выражения, если я настроил его для проверки диапазона 10 лет? Обратите внимание, что размер растет экспоненциально. Я пробовал с интервалом в 4 месяца, но я получил сообщение об ошибке/предупреждении о том, что выражение слишком велико.
Поскольку регулярное выражение слишком длинное, я не могу сделать его онлайн-демонстрацию, но здесь код в PHP:

$string = '20130101-20130101
20130201-20130101
20130105-20130120
20130201-20130301
20130210-20130215
20130301-20130301
20130301-20130201
'; // A sample

$regex = file_get_contents('regex.txt'); // Get the regex from a file (which we generated previously)
preg_match_all('#'.$regex.'#', $string, $matches); // Let regex !
print_r($matches[0]); // Printing the matches ...

Вывод:

Array
(
    [0] => 20130101-20130101
    [1] => 20130105-20130120
    [2] => 20130201-20130301
    [3] => 20130210-20130215
    [4] => 20130301-20130301
)

Онлайн-дамп регулярного выражения       Онлайн-демонстрация PHP

Заключение

Пожалуйста, никогда не думайте об использовании regex для этой задачи, иначе у вас было бы 10 проблем:)

Ответ 2

Вместо того, чтобы писать свой собственный компонент для проверки, вы можете использовать BizTalk Business Rules Engine Pipeline Framework в сочетании с политикой BRE для подтвердите диапазон дат.

Полное раскрытие: эта структура написана моим коллегой.