Expression régulière pour rechercher uniquement en majuscules "mots", avec quelques exceptions

j'ai des chaînes de caractères comme suit:

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

je voudrais faire correspondre avec une expression régulière ces seuls mots en majuscules (à savoir ici P1 et J236). Le problème est que je ne veux pas correspondre à la première lettre de la phrase quand il s'agit d'une lettre du mot.

Exemple:

"A thing P1 must connect ..." 

je veux P1 seulement, pas A et P1. En faisant cela, je sais que je peux manquer d'un vrai "mot" (comme dans "X must connect to Y"), mais je peux vivre avec elle.

de plus, Je ne veux pas faire correspondre les mots en majuscules si la phrase est en majuscules.

Exemple:

"THING P1 MUST CONNECT TO X2."

bien sûr, idéalement, je voudrais correspondre les mots techniques P1 et X2 ici mais comme ils sont "cachés" dans la phrase en majuscules et que ces mots techniques n'ont pas de motif spécifique, c'est impossible. Encore une fois, je peux vivre avec parce que toutes les phrases en majuscules ne sont pas si fréquentes dans mon fichier.

Merci!

21
demandé sur Pavlo Zhukov 2011-01-04 23:54:40

6 réponses

dans une certaine mesure, cela va varier en fonction de la "saveur" du RegEx que vous utilisez. Ce qui suit est basé sur .net RegEx, qui utilise \b pour les limites des mots. Dans le dernier exemple, il utilise aussi négatif lookaround (?<!) et (?!) ainsi que des parenthèses non-capturantes (?:)

fondamentalement, cependant, si les termes contiennent toujours au moins une lettre majuscule suivie d'au moins un nombre, vous pouvez utiliser

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

pour tous-majuscules et nombres (total doit être de 2 ou plus):

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

Pour les majuscules et les chiffres, en commençant par au moins une lettre:

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

Le grand-père, pour retourner les articles qui ont n'importe quelle combinaison de lettres majuscules et de chiffres, mais qui ne sont pas d'une seule lettre au début d'une ligne et qui ne font pas partie d'une ligne qui est tout en majuscules:

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

composition:

le regex commence par (?:. ?: signifie que -- bien que ce qui suit soit entre parenthèses, Je ne suis pas intéressé à capturer le résultat. C'est ce qu'on appelle "les parenthèses qui ne sont pas capturées."Ici, j'utilise les paréthèses parce que j'utilise l'alternance (voir ci-dessous).

à l'intérieur des parens non-capturing, j'ai deux clauses séparées séparées par le symbole de pipe |. C'est l'alternance -- comme un "ou". Le regex peut correspondre à la première expression ou la seconde. Les deux cas sont ici "c'est le premier mot de la ligne" ou "tout le reste", parce que nous avons l'exigence spéciale de l'exclusion des mots d'une lettre au début de la ligne.

Maintenant, regardons chaque expression dans l'alternance.

La première expression est: (?<!^)[A-Z]\b. La proposition principale est ici [A-Z]\b, qui est n'importe quelle lettre majuscule suivie d'une limite de mot, qui pourrait être ponctuation, espace blanc, linebreak, etc. La partie avant qui est (?<!^), qui est un " lookbehind négatif."C'est un zéro-largeur assertion, ce qui signifie qu'il ne "consomme" pas de personnages dans le cadre d'un match -- pas vraiment important de le comprendre ici. La syntaxe pour lookbehind négatif dans .NET est (?<!x), où x est l'expression qui doit existe avant notre clause principale. Ici, cette expression est tout simplement ^, ou début de ligne, donc ce côté de l'alternance se traduit par " tout mot composé d'une seule lettre majuscule qui est au début de la ligne."

D'accord, donc on fait correspondre des mots d'une lettre, des majuscules qui ne sont pas au début de la ligne. Nous devons toujours apparier les mots composés de tous les nombres et des lettres majuscules.

qui est traitée par une portion relativement petite de la deuxième expression dans l'alternance: \b[A-Z0-9]+\b. \b s représentent les limites des mots, et le [A-Z0-9]+ correspond à un ou plusieurs chiffres et lettres majuscules.

Le reste de l'expression se compose de d'autres lookarounds. (?<!^[A-Z0-9 ]*) est un autre négatif lookbehind, où l'expression est ^[A-Z0-9 ]*. Cela signifie que ce qui précède ne doit pas être toutes les lettres majuscules et les chiffres.

The second Look Around is (?![A-Z0-9 ]$), qui est une anticipation négatif. Cela signifie ce qui suit doit être en lettres majuscules et de chiffres.

donc, dans l'ensemble, nous capturons les mots de toutes les lettres et de tous les nombres en majuscules, et excluons les caractères majuscules et une lettre du début de la ligne et le tout, des lignes qui sont tous en majuscules.

il y a au moins une faiblesse ici dans le fait que les lookarounds dans la seconde expression d'alternance agissent indépendamment, donc une phrase comme "un P1 devrait se connecter au J9" va correspondre à J9, mais pas à P1, parce que tout avant P1 est capitalisé.

il est possible de contourner ce problème, mais cela triplerait presque la longueur de la regex. Essayer de faire autant dans un seul regex est rarement, si jamais, justifié. Il est préférable de scinder le travail en plusieurs regexes ou en une combinaison de commandes de traitement regex et string standard dans le langage de programmation de votre choix.

41
répondu Jay 2011-01-06 16:37:51

Pourquoi avez-vous besoin de faire cela dans un monster-regex? Vous pouvez utiliser le code réel pour mettre en œuvre certaines de ces règles, et le faire serait beaucoup plus facile à modifier si ces exigences changent plus tard.

Par exemple:

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

# Carry on with matching uppercase terms
2
répondu Anon. 2011-01-04 21:00:41

Je ne suis pas un gourou de regex. Mais essayer:

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

Je n'essaierai pas les points bonus de toute la phrase en majuscules. hehe

2
répondu Craig Celeste 2011-01-04 21:07:30

peut-être Pouvez-vous lancer ce regex en premier pour voir si la ligne est tous les caps:

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

Qui correspond seulement si c'est une ligne comme THING P1 MUST CONNECT TO X2.

sinon, vous devriez être en mesure de retirer les phrases en majuscules individuelles avec ceci:

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

Qui doit correspondre à "P1" et "J236" dans The thing P1 must connect to the J236 thing in the Foo position.

2
répondu Upgradingdave 2011-01-04 21:12:24

ne faites pas des choses comme [A-Z] ou [0-9]. N' \p{Lu} et \d à la place. Bien sûr, Ceci est valable pour les saveurs de regex à base de perl. Cela inclut java.

je suggère que vous ne faites pas un énorme regex. D'abord diviser le texte en phrases. puis marquer (divisé en mots). Utiliser une regex pour vérifier chaque jeton/mot. Sautez le premier jeton de la phrase. Vérifiez si tous les jetons sont en majuscules à l'avance et sautez la phrase entière si c'est le cas, ou modifiez le regex dans ce cas.

2
répondu Radu Simionescu 2013-02-12 16:24:16

Pour le premier cas, vous proposer, vous pouvez utiliser: '[[:blank:]]+[A-Z0-9]+[[:blank:]]+', par exemple:

echo "La chose P1 doit se connecter à la J236 chose dans le Foo position" | grep -oE '[[:blank:]]+[A-Z0-9]+[[:blank:]]+'

dans le second cas peut-être vous avez besoin d'utiliser autre chose et pas un regex, peut-être un script avec un dictionnaire de mots techniques...

Santé, Fernando!--1-->

1
répondu Fernando 2011-01-04 21:00:26