web-dev-qa-db-fra.com

Regex pour détecter si tous les caractères alphabétiques sont en majuscules

Comment pourrais-je détecter si tous les caractères alphabétiques d'une chaîne (de> = 2 caractères) sont en majuscules? En fin de compte, j'essaie de filtrer les noms de titre de chapitre, qui sont des lignes de mon ensemble de données. Donc, si un titre de chapitre est "ARYA", je veux qu'il soit détecté, comme "LA MAIN DE LA REINE".

Voici ce que j'essaie mais ne fonctionne pas:

library(dplyr)
library(stringr)

str_detect("THE QUEEN’S HAND", "^[[:upper:]]{2,}+$")
#> FALSE

Les exigences dont j'ai besoin:

  • Nombre de caractères> = 2 parce que j'utilise finalement cela pour filtrer les noms de chapitre, mais parfois il y a une ligne où le mot est "I", mais ce n'est pas un chapitre - c'est juste un mot. Bien que cela puisse être filtré à un point différent
  • Seuls les caractères alphabétiques ou apostrophes ont été détectés. Parfois, la ligne est "...", que je ne veux pas détecter. Cependant, si j'utilise une solution toupper(x) == (x), cela serait détecté à côté de quelque chose comme "LA MAIN DE LA REINE". J'essaie également de me débarrasser de tout ce qui comporte des points ou des points d'exclamation, comme "ARRÊTEZ CECI!
15
Evan O.

Inversez votre logique

tous les caractères alphabétiques sont en majuscules.

est le même que

pas un seul caractère alphabétique n'est en minuscule.

Code

Si vous voulez vraiment utiliser une expression régulière pour cette tâche, tout ce que vous devez écrire est:

! str_detect("THE QUEEN’S HAND", "[[:lower:]]")

Vous pouvez le tester ici .

Si vous souhaitez prendre en compte la longueur de la chaîne, vous pouvez ajouter un OU logique :

nchar(str) < 2 || ! str_detect(str, "[[:lower:]]")

Vous pouvez le tester ici .

15
Eric Duminil

Vous faites probablement (?) Cela au mauvais stade de votre analyse

Il semble que vous essayez de faire une analyse textuelle d'ASOIAF et d'exclure les titres de chapitre de votre analyse, mais je pense que vous essayez de le faire au mauvais moment de l'analyse. Les en-têtes de chapitre sont faciles à identifier dans le texte d'origine car ils sont toujours en haut de la page, toujours centrés et toujours suivis d'un espace. Ces fonctionnalités vous permettraient d'identifier facilement et de manière fiable les titres, mais ces informations ont été supprimées avant que vous ne tentiez d'identifier les titres. Si vous contrôlez cette étape de l'analyse, il vous sera probablement plus facile de déterminer quelles entrées sont des en-têtes à ce stade.

Vous n'avez pas besoin de Regex pour cela

Bien que vous spécifiez Regex dans le titre de la question, il n'est pas inclus dans le corps de la question, je suppose donc que vous n'en avez pas réellement besoin mais que vous avez simplement fini par rechercher une solution Regex à un problème où il n'est pas nécessaire.

Le moyen le plus simple de tester toutes les lettres majuscules est de faire x == toupper(x). toupper() convertira tous les caractères alphabétiques dans leur forme majuscule, vous pouvez ensuite tester si votre chaîne est entièrement en majuscule en la comparant à cette version transformée.

Le filtrage des chaînes de longueur inférieure à 2 est également facile, vous pouvez le faire simplement en ajoutant une condition nchar(x) >=2.

Votre dernière exigence est moins triviale, mais vous devrez déterminer exactement la condition à exclure. Je soupçonne que si vous obtenez des paragraphes complets (?), La meilleure chose serait de rechercher des guillemets. Selon la gamme d'options qui doivent être mises en correspondance, vous devrez peut-être utiliser Regex ici après tout, mais si ce n'est que quelques marques spécifiques, vous pouvez utiliser str_detect (À partir du package stringr) avec l'option fixed() pour le détecter car cela sera considérablement plus rapide.

Peu importe que vous utilisiez Regex pour cette étape finale, j'envelopperais la détection dans une série de conditions dans une fonction plutôt que de faire une seule recherche Regex car cela sera plus rapide et, à mon avis, conceptuellement plus facile à comprendre.

13
Jack Aidley

Modifier:

J'ai d'abord pensé que vous vouliez ignorer les lettres minuscules si leur longueur est <2. Si vous voulez vous assurer que toutes les lettres sont en majuscules mais seulement si la longueur de la chaîne entière est> = 2, une expression rationnelle beaucoup plus simple le ferait:

^(?:[A-Z](?:[^A-Za-z\r\n])*){2,}$

Démo .

Ou si vous souhaitez faire correspondre une chaîne de longueur> = 2 même si elle ne contient qu'une seule lettre (par exemple, "A @"):

^(?=.{2})(?:[A-Z](?:[^A-Za-z\r\n])*)+$

ne autre démo .


Réponse originale:

Voici une solution uniquement regex qui vérifie uniquement si les caractères sont en majuscules s'ils sont> = 2:

^(?:[A-Z]{2,}(?:[^A-Za-z\r\n]|[A-Za-z](?![a-z]))*)+$

Essayez-le en ligne .

Ou:

^(?:[[:upper:]]{2,}(?:[^[:alpha:]\r\n]|[[:alpha:]](?![[:lower:]]))*)+$

Essayez-le en ligne .

Ventilation:

  • ^: Affirme la position au début de la ligne/chaîne.
  • (?:: Début du premier groupe non capturant.
    • [A-Z]: Correspond à n'importe quelle lettre majuscule anglais lettre.1
    • {2,}: Correspond deux fois ou plus au caractère précédent.
    • (?:: Début du deuxième groupe non capturant.
      • [^A-Za-z\r\n]: Correspond à tout caractère qui n'est pas une lettre English ou un terminateur de ligne.2
      • |: Ou.
      • [A-Za-z]: Correspond à n'importe quelle lettre English.3
      • (?!: Début d'un Lookahead négatif.
        • [a-z]: Correspond à n'importe quelle lettre minuscule anglais lettre.4
      • ): Fin de l'anticipation négative.
    • ): Fin du deuxième groupe non capturant.
    • *: Correspond à zéro ou plusieurs fois du groupe précédent.
  • ): Fin du premier groupe non capturant.
  • +: Correspond à une ou plusieurs fois du groupe précédent.
  • $: Affirme la position à la fin de la ligne/chaîne

Remarque: pour traiter la chaîne entière comme une seule ligne, supprimez simplement le \r\n partie.


  1. Utilisation [[:upper:]] à la place, si vous souhaitez faire correspondre des lettres non anglaises.
  2. Utilisation [^[:alpha:]\r\n] à la place, si vous souhaitez faire correspondre des lettres non anglaises.
  3. Utilisation [[:alpha:]] à la place, si vous souhaitez faire correspondre des lettres non anglaises.
  4. Utilisation [[:lower:]] à la place, si vous souhaitez faire correspondre des lettres non anglaises.
10

La façon dont je comprends cela:

  • si la longueur de la chaîne entière est <2, tout se passe.
  • sinon, la chaîne peut avoir n'importe quoi sauf des caractères minuscules.

Avec cela, je pense que ce regex devrait suffire:

^(.|[^[:lower:]]{2,})$

Quelle est la disjonction de

  • Caractère unique, tout se passe: ^.$
  • Plusieurs caractères, uniquement en minuscules: ^[^[:lower:]]{2,}$

L'essayer:

> str_detect("THE QUEEN’S HAND", "^(.|[^[:lower:]]{2,})$")
[1] TRUE
> str_detect("THE QUEEN’S HaND", "^(.|[^[:lower:]]{2,})$")
[1] FALSE
> str_detect("i", "^(.|[^[:lower:]]{2,})$")
[1] TRUE
> str_detect("I", "^(.|[^[:lower:]]{2,})$")
[1] TRUE
> str_detect("ii", "^(.|[^[:lower:]]{2,})$")
[1] FALSE
5
muru

MODIFIER

Pour prendre en compte le nombre de caractères de la chaîne, nous pouvons utiliser nchar avec ifelse sans changer l'expression régulière.

str <- "THE QUEEN'S HAND"
ifelse(nchar(str) >= 2 , grepl("^[A-Z]+$" , gsub("[^A-Za-z]","", str)), FALSE)
#[1] TRUE

str <- "THE QUEEN's HAND"
ifelse(nchar(str) >= 2 , grepl("^[A-Z]+$" , gsub("[^A-Za-z]","", str)), FALSE)
#[1] FALSE

str <- "T"
ifelse(nchar(str) >= 2 , grepl("^[A-Z]+$" , gsub("[^A-Za-z]","", str)), FALSE)
#[1] FALSE

Ou, comme l'a commenté @Konrad Rudolph, nous pouvons éviter la vérification ifelse en utilisant l'opérateur logique.

str <- c("THE QUEEN'S HAND", "THE QUEEN's HAND", "T")
nchar(str) >= 2 & grepl("^[A-Z]+$" , gsub("[^A-Za-z]","", str))
#[1]  TRUE FALSE FALSE

Réponse originale

Nous remplaçons d'abord tous les caractères non alphabétiques par un espace vide ("") par gsub, puis le comparons avec toupper.

text = gsub("[^a-zA-Z]+", "", "THE QUEENS HAND")

text
#[1] "THEQUEENSHAND"

text == toupper(text)
#[1] TRUE

Pour une chaîne en minuscules, elle renverra FALSE

text = gsub("[^a-zA-Z]+", "", "THE QUEENs HAND")
text == toupper(text)
#[1] FALSE

Et comme @SymbolixAU l'a commenté, nous ne pouvons garder le tout en tant que regex qu'en utilisant grepl et gsub

grepl("^[A-Z]+$" , gsub("[^A-Za-z]","", "THE QUEEN'S HAND"))
#[1] TRUE

grepl("^[A-Z]+$" , gsub("[^A-Za-z]","", "THE QUEEN's HAND"))
#[1] FALSE
4
Ronak Shah

Si je comprends bien votre question, vous souhaitez accepter des chaînes qui:

  1. Sont deux caractères ou plus.
  2. Ne contient pas de lettres minuscules.

Si c'est correct, vous n'êtes pas loin de la bonne réponse. Mais la vôtre n'accepte que des lettres majuscules au lieu d'accepter autre chose que des caractères minuscules.

Le regex suivant devrait fonctionner:

^[^[:lower:]]{2,}+$
3
Édouard

Pour rester dans le contexte stringr, utilisez str_replace_all pour obtenir uniquement les caractères alphabétiques, puis str_detect pour vérifier les majuscules:

string1 <- "THE QUEEN’S HAND"
string2 <- "T"

string1 %>%
  str_replace_all(., "[^a-zA-Z]", "") %>%
  str_detect(., "[[:upper:]]{2,}")
# TRUE

string2 %>%
  str_replace_all(., "[^a-zA-Z]", "") %>%
  str_detect(., "[[:upper:]]{2,}")
# FALSE
2
andrew_reece