Подтвердить что ты не робот

Регулярное выражение соответствует только прописным "словам" с некоторыми исключениями

У меня есть технические строки:

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

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

Пример: in:

"A thing P1 must connect ..." 

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

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

Пример:

"THING P1 MUST CONNECT TO X2."

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

Спасибо!

4b9b3361

Ответ 1

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

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

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

Для всех прописных и цифр (общее количество должно быть 2 или более):

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

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

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

The granddaddy, чтобы возвращать элементы, которые имеют любую комбинацию прописных букв и цифр, но которые не являются одиночными буквами в начале строки и которые не являются частью строки, которая имеет все прописные буквы:

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

пробоя:

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

Например:

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

# Carry on with matching uppercase terms

Ответ 3

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

^[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.

Ответ 4

Не делайте такие вещи, как [A-Z] или [0-9]. Вместо этого выполняем \p {Lu} и \d. Конечно, это справедливо для ароматизаторов regex на основе perl. Это включает java.

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

Ответ 5

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

echo "То, что P1 должно подключиться к J236 в позиции Foo" | grep -oE '[[: blank:]] + [A-Z0-9] + [[: blank:]] +'

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

Приветствия, Фернандо

Ответ 6

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

<[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

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