У меня есть следующая рабочая функция, которая используется в контрольном ограничении (я опубликую только соответствующую часть SQL):
-- a comma should always be followed by a space
-- a period should always be followed by a space, except if it is the last character of the string OR the string contains 'caporal'
-- a question mark should always be followed by a space, except if it is the last character of the string
-- must not contain 2 or more spaces in a row
-- must not contain ((
-- must not contain ))
-- any open parenthesis should be closed: number of '(' should equal to number of ')'
SELECT
($1 !~ ',(?!\s)|\s{2}|[?](?!\s(?!$)|$)|[()]{2,}') AND
((array_length(string_to_array($1, '('), 1) - 1) = (array_length(string_to_array($1, ')'), 1) - 1)) AND
($1 ~ 'caporal' OR $1 !~ '[.](?!\s(?!$)|$)')
Со временем я понял, что мне нужно разрешить период без следующего места для дел:
.fr
.com
.net
.co.uk
Кроме того, я понял, что мне нужно разрешить запись чисел с плавающей запятой с запятой/точкой в качестве разделителя. Должны быть допустимы следующие случаи:
2,5cm
10.4l
Я пробовал несколько вещей, но, похоже, я просто нарушаю существующие правила, а не добавляю к ним «исключения».
Моя последняя попытка заключалась в следующем:
SELECT
($1 !~ '[[a-zA-Z]àâçéèêëîïôûùüÿæœ],(?!\s)|\s{2}|[?](?!\s(?!$)|$)|[()]{2,}') AND
((array_length(string_to_array($1, '('), 1) - 1) = (array_length(string_to_array($1, ')'), 1) - 1)) AND
($1 ~ 'caporal' OR $1 !~ '[[a-zA-Z]àâçéèêëîïôûùüÿæœ][.](?!\s(?!$)|(?!fr)|(?!com)|$)')
Но это явно не то, что я хочу. Заранее спасибо за подсказки и советы!
Вы должны изменить первое регулярное выражение на
,(?!\d(?<=\d,\d)|\s)|\s{2}|\?(?!\s(?!$)|$)|[()]{2,}
и последний, чтобы
\.(?!\d(?<=\d\.\d)|(?:fr|com|co\.uk|(?<=\yco\.)uk|net)\y|\s(?!$)|$)
Изменения являются дополнениями к отрицательным прогнозам, которые не находят соответствия, если их шаблоны совпадают непосредственно справа от текущего местоположения.
В первом случае ,(?!\d(?<=\d,\d)|\s)
используется для соответствия любой запятой, за которой не следует пробел, или любой цифре, которая является дробной цифрой (поскольку ей должна предшествовать цифра и запятая).
Во втором регулярном выражении добавляется аналогичное ограничение, см. \d(?<=\d\.\d)
, которое заставляет \.
соответствовать точке, которая не является первой дробной цифрой в числе с плавающей запятой с точкой в качестве десятичного разделителя, а часть (?:fr|com|co\.uk|(?<=\yco\.)uk|net)\y
добавляется, чтобы избежать совпадения с .
за которым следуют fr
, com
, co.uk
, вторая точка в co.uk
((?<=\yco\.)uk
просмотр назад гарантирует, что запятая перед uk
, которой не предшествует co.
, все еще совпадает) или net
как целые слова (см. \y
, граница слова).
Попробуйте изменить первое регулярное выражение на
,(?!\d(?<=\d,\d)|\s)|\s{2}|\?(?!\s(?!$)|$)|[()]{2,}
, а последнее на\.(?!\d(?<=\d\.\d)|(?:fr|com|co\.uk|(?<=\yco\.)uk|net)\y|\s(?!$)|$)
. Это должно сделать работу.