php regex – найти строчную строку с номером и пробелами в тексте

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

Например, из этого текста "some text to contain EXAM PL E 7STRING uppercase word" Я хочу получить EXAM PL E 7STRING ,

найденная строка должна начинаться и заканчиваться только в верхнем регистре, но в середине, без прописных букв может также содержать (но не обязательно) одно число и пробелы. Итак, регулярное выражение должно соответствовать любому из этих шаблонов

 1) EXAMPLESTRING - just uppercase string 2) EXAMP4LESTRING - with number 3) EXAMPLES TRING - with space 4) EXAM PL E STRING - with more than one spaces 5) EXAMP LE4STRING - with number and space 6) EXAMP LE 4ST RI NG - with number and spaces 

и с общей длиной строки должно быть равно или больше 4 букв

Я написал это регулярное выражение '/[AZ]{1,}([AZ\s]{2,}|\d?)[AZ]{1,}/' , которое может найти первые 4 шаблона, но я не могу понять это должно совпадать и с последними 2 шаблонами.

благодаря

Существует аккуратный трюк, называемый lookahead . Он просто проверяет, что следует за текущей позицией. Это можно использовать для проверки нескольких условий:

 '/(?<![AZ])(?=(?:[AZ][\s\d]*){3}[AZ])(?!(?:[AZ\s]*\d){2})[AZ][AZ\s\d]*[AZ]/' 

Первый обратный вызов – это, фактически, lookbehind и проверяет, нет ли предыдущей прописной буквы. Это всего лишь небольшое ускорение для строк, которые в любом случае потерпят неудачу. Второй lookaound (lookahead) проверяет, что есть как минимум четыре буквы. Третий проверяет, нет ли двух цифр. Остальное просто соответствует строке допустимых символов, начиная и заканчивая буквой в верхнем регистре.

Обратите внимание, что в случае двух цифр это не будет соответствовать вообще (вместо того, чтобы сопоставлять все со второй цифрой). Если вы хотите совместить в таком случае, вы можете включить правило «1 разряд» в фактическое совпадение:

 '/(?<![AZ])(?=(?:[AZ][\s\d]*){3}[AZ])[AZ][AZ\s]*\d?[AZ\s]*[AZ]/' 

РЕДАКТИРОВАТЬ:

Как отметил Ωmega, это вызовет проблемы, если перед второй цифрой будет меньше четырех букв, но больше после этого. Это на самом деле довольно сложно, потому что утверждение должно быть, что перед второй цифрой имеется более 4 букв. Поскольку мы не знаем, где первая цифра встречается в этих четырех письмах, мы должны проверить все возможные позиции. Для этого я вообще покончил бы с взглядами и просто предоставил бы три различные альтернативы. (Я буду держать lookbehind как оптимизацию для несогласованных частей.)

 '/(?<![AZ])[AZ]\s*(?:\d\s*[AZ]\s*[AZ]|[AZ]\s*\d\s*[AZ]|[AZ]\s*[AZ][AZ\s]*\d?)[AZ\s]*[AZ]/' 

Или здесь с добавленными комментариями:

 '/ (?<! # negative lookbehind [AZ] # current position is not preceded by a letter ) # end of lookbehind [AZ] # match has to start with uppercase letter \s* # optional spaces after first letter (?: # subpattern for possible digit positions \d\s*[AZ]\s*[AZ] # digit comes after first letter, we need two more letters before last one | # OR [AZ]\s*\d\s*[AZ] # digit comes after second letter, we need one more letter before last one | # OR [AZ]\s*[AZ][AZ\s]*\d? # digit comes after third letter, or later, or not at all ) # end of subpattern for possible digit positions [AZ\s]* # arbitrary amount of further letters and whitespace [AZ] # match has to end with uppercase letter /x' 

Это дает тот же результат на длинном тестовом входе Ωmega.

Я предлагаю использовать шаблон регулярного выражения

 [AZ][ ]*(\d)?(?(1)(?:[ ]*[AZ]){3,}|[AZ][ ]*(\d)?(?(2)(?:[ ]*[AZ]){2,}|[AZ][ ]*(\d)?(?(3)(?:[ ]*[AZ]){2,}|[AZ][ ]*(?:\d|(?:[ ]*[AZ])+[ ]*\d?))))(?:[ ]*[AZ])* 

(см. эту демонстрацию ).

 [AZ][ ]*(?:\d(?:[ ]*[AZ]){2}|[AZ][ ]*\d[ ]*[AZ]|(?:[AZ][ ]*){2,}\d?)[AZ ]*[AZ] 

(см. эту демонстрацию )