Regex для соответствия только прописным «словам» с некоторыми исключениями - PullRequest
25 голосов
/ 04 января 2011

У меня есть следующие технические строки:

"The thing P1 must connect to the J236 thing in the Foo position."

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

Пример:

"A thing P1 must connect ..." 

Я хочу P1только не A и P1.Делая это, я знаю, что могу пропустить настоящее «слово» (как в "X must connect to Y"), но я могу жить с этим.

Кроме того, я не хочу сопоставлять слова в верхнем регистре, если все предложение в верхнем регистре.

Пример:

"THING P1 MUST CONNECT TO X2."

Конечно, в идеале я хотел бысопоставьте здесь технические слова P1 и X2, но поскольку они «спрятаны» в заглавном предложении и поскольку эти технические слова не имеют определенного шаблона, это невозможно.Снова я могу жить с этим, потому что предложения в верхнем регистре не так часто встречаются в моих файлах.

Спасибо!

Ответы [ 6 ]

52 голосов
/ 04 января 2011

В некоторой степени это будет зависеть от "аромата" RegEx, который вы используете.Следующее основано на .NET RegEx, который использует \b для границ слов.В последнем примере он также использует отрицательный обход (?<!) и (?!), а также не захватывающие скобки (?:)

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

\b[A-Z]+[0-9]+\b

для всех заглавных букв и цифр (всего должно быть 2 или более):

\b[A-Z0-9]{2,}\b

для всех заглавных букв и цифр, но начиная схотя бы одна буква:

\b[A-Z][A-Z0-9]+\b

Дедушка, чтобы вернуть элементы, которые имеют любую комбинацию прописных букв и цифр, но которые не являются одиночными буквами в начале строки и не являются частью строкивсе в верхнем регистре:

(?:(?<!^)[A-Z]\b|(?<!^[A-Z0-9 ]*)\b[A-Z0-9]+\b(?![A-Z0-9 ]$))

разбивка:

Регулярное выражение начинается с (?:.?: означает, что - хотя то, что следует в скобках, я не заинтересован в получении результата.Это называется "не захватывая скобки".Здесь я использую паретезы, потому что я использую чередование (см. Ниже).

Внутри необъявленных паренов у меня есть два отдельных предложения, разделенных символом трубы |.Это чередование - как «или».Регулярное выражение может соответствовать первому выражению или второму.Здесь есть два случая: «это первое слово строки» или «все остальное», потому что у нас есть специальное требование исключения однобуквенных слов в начале строки.

Теперь давайте посмотримна каждое выражение в чередовании.

Первое выражение: (?<!^)[A-Z]\b.Основным предложением здесь является [A-Z]\b, то есть любая заглавная буква, за которой следует граница слова, которая может быть пунктуацией, пробелом, переводом строки и т. Д. Перед ней стоит (?<!^), что является «отрицательным взглядом сзади».Это утверждение нулевой ширины, которое означает, что оно не «потребляет» символы как часть совпадения - не очень важно понимать это здесь.Синтаксис отрицательного внешнего вида в .NET: (?<!x), где x - это выражение, которое должно , а не существовать до нашего основного предложения.Здесь это выражение просто ^, или начало строки, поэтому эта сторона чередования переводится как «любое слово, состоящее из одной заглавной буквы, которая не в начале строки."

Хорошо, мы сопоставляем прописные слова из одной буквы, которые не находятся в начале строки.Нам все еще нужно сопоставить слова, состоящие из всех цифр и заглавных букв.

Это обрабатывается относительно небольшой частью второго выражения в чередовании: \b[A-Z0-9]+\b.\b s представляют границы слов, а [A-Z0-9]+ соответствует одному или нескольким цифрам и заглавным буквам вместе.

Остальная часть выражения состоит из других обходных путей.(?<!^[A-Z0-9 ]*) - еще один негативный взгляд сзади, где выражение ^[A-Z0-9 ]*.Это означает, что предшествующими должны быть не все заглавные буквы и цифры.

Второй обходной путь - (?![A-Z0-9 ]$), что является негативным прогнозом.Это означает, что последующее должно , а не быть всеми заглавными буквами и цифрами.

Итак, мы собираем слова всех заглавных букв и цифр и исключаем однобуквенные прописные буквы изначало строки и все, что в строках, которые все в верхнем регистре.

Здесь есть как минимум один недостаток в том, что обходные пути во втором выражении чередования действуют независимо, поэтому предложение типа «A P1 должно соединиться с J9"будет соответствовать J9, но не P1, потому что все до P1 пишется с заглавной буквы.

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

3 голосов
/ 12 февраля 2013

Не делайте такие вещи, как [AZ] или [0-9].Сделайте \ p {Lu} и \ d вместо этого.Конечно, это верно для регулярных выражений на основе Perl.Это включает в себя Java.

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

3 голосов
/ 05 января 2011

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

^[A-Z \d\W]+$

Это будет соответствовать, только если это строка типа THING P1 MUST CONNECT TO X2.

В противном случае вы должны быть в состоянии извлечь отдельные заглавные фразы с помощью этого:

[A-Z][A-Z\d]+

Это должно соответствовать "P1" и "J236" в The thing P1 must connect to the J236 thing in the Foo position.

3 голосов
/ 05 января 2011

Зачем вам нужно сделать это в одном монстре-регулярном выражении? Вы можете использовать реальный код для реализации некоторых из этих правил, и это будет намного легче изменить, если эти требования изменятся позже.

Например:

if(/^[A-Z0-9\s]*$/)
    # sentence is all uppercase, so just fail out
    return 0;

# Carry on with matching uppercase terms
2 голосов
/ 05 января 2011

Я ни в коем случае не гуру регулярных выражений.Но попробуйте:

<[A-Z0-9][A-Z0-9]+>

<           start of word
[A-Z0-9]    one character
[A-Z0-9]+   and one or more of them
>           end of word

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

1 голос
/ 05 января 2011

Для первого предложенного вами случая вы можете использовать: '[[: blank:]] + [A-Z0-9] + [[: blank:]] +', например:

echo«Объект P1 должен подключиться к устройству J236 в положении Foo» |grep -oE '[[: blank:]] + [A-Z0-9] + [[: blank:]] +'

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

Cheers, Fernando

...