J'essaie d'écrire une expression régulière qui affichera tous les mots de 10 caractères et aucune des lettres ne se répète.
Jusqu'à présent, j'ai
grep --colour -Eow '(\w{10})'
C'est la toute première partie de la question. Comment pourrais-je procéder pour vérifier le «caractère unique»? Je n'ai vraiment aucune idée, à part cela, j'ai besoin d'utiliser des références arrières.
grep
regular-expression
Dylan Meeus
la source
la source
Réponses:
exclut les mots qui ont deux caractères identiques.
exclut ceux qui ont des caractères répétitifs.
POSIX:
tr
place les mots sur leur propre ligne en convertissant toute séquation de caractères autres que des mots ( ccomplément alphanumérique et trait de soulignement) en caractère de nouvelle ligne.Ou avec un
grep
:(exclure les lignes de moins de 10 et de plus de 10 caractères et celles dont le caractère apparaît au moins deux fois).
Avec un
grep
seul (GNU grep avec support PCRE oupcregrep
):C'est-à-dire, une limite de mot (
\b
) suivie d'une séquence de 10 caractères de mot (à condition que chacun ne soit pas suivi d'une séquence de caractères de mot et eux-mêmes, en utilisant l'opérateur PCRE d'anticipation négative(?!...)
).Nous avons de la chance que cela fonctionne ici, car peu de moteurs d'expression rationnelle fonctionnent avec des références inverses à l'intérieur de parties répétitives.
Notez que (avec ma version de GNU grep au moins)
Ne fonctionne pas, mais
fait (comme
echo aa | grep -Pw '(.)\2'
) ce qui ressemble à un bug.Vous voudrez peut-être:
si vous voulez
\w
ou\b
considérez n'importe quelle lettre comme un composant de mot et pas seulement celles ASCII dans les locales non ASCII.Une autre alternative:
Il s'agit d'une limite de mot (celle qui n'est pas suivie d'une séquence de caractères de mot dont l'un se répète) suivie de 10 caractères de mot.
Choses à avoir éventuellement à l'esprit:
Babylonish
par exemple serait appariée, car tous les caractères sont différents même s'il y a deuxB
s, un minuscule et un majuscule (utilisez-i
pour changer cela).-w
,\w
et\b
, un mot est une lettre (celles ASCII uniquement pour GNUgrep
pour le moment , la[:alpha:]
classe de caractères dans vos paramètres régionaux si vous utilisez-P
et(*UCP)
), des chiffres décimaux ou un trait de soulignement .c'est
(deux mots selon la définition française d'un mot) ouit's
(un mot selon certaines définitions anglaises d'un mot) ourendez-vous
(un mot selon la définition française d'un mot) ne sont pas considérés comme un mot.(*UCP)
, les caractères de combinaison Unicode ne sont pas considérés comme des composants de mots, donctéléphone
($'t\u00e9le\u0301phone'
) est considéré comme 10 caractères, dont un non alpha.défavorisé
($'d\u00e9favorise\u0301'
) serait apparié même s'il y en a deux,é
car il s'agit de 10 caractères alpha différents, suivis d'un accent aigu combiné (non alpha, il y a donc une limite de mot entre lee
et son accent).la source
\w
ne correspond pas-
cependant.D'accord ... voici la méthode maladroite pour une chaîne de cinq caractères:
Parce que vous ne pouvez pas mettre une référence arrière dans une classe de caractères (par exemple
[^\1|\2]
), vous devez utiliser une anticipation négative -(?!foo)
. Il s'agit d'une fonction PCRE, vous avez donc besoin du-P
commutateur.Le modèle pour une chaîne de 10 caractères sera beaucoup plus long, bien sûr, mais il existe une méthode plus courte utilisant une correspondance de n'importe quoi de longueur variable ('. *') Dans l'anticipation:
Après avoir lu la réponse éclairante de Stéphane Chazelas, je me suis rendu compte qu'il existe un modèle simple similaire pour cela utilisable via le
-v
commutateur de grep :Étant donné que la vérification procède un caractère à la fois, cela verra si un caractère donné est suivi par zéro ou plusieurs caractères (
.*
), puis une correspondance pour la référence arrière.-v
inverse, n'imprimant que les éléments qui ne correspondent pas à ce modèle. Cela rend les références arrières plus utiles car elles ne peuvent pas être annulées avec une classe de caractère, et de manière significative:fonctionnera pour identifier une chaîne de n'importe quelle longueur avec des caractères uniques alors que:
ne le fera pas, car il correspondra à tout suffixe avec des caractères uniques (par exemple,
abcabc
correspond à cause deabc
à la fin et àaaaa
cause dea
la fin - d'où toute chaîne). Il s'agit d'une complication causée par des contournements de largeur nulle (ils ne consomment rien).la source
(.)(?!.*\1)(.)(?!.*\2)(.)(?!.*\3)(.)(?!\4).
Si vous n'avez pas besoin de faire tout cela en regex, je le ferais en deux étapes: d'abord faire correspondre tous les mots de 10 lettres, puis les filtrer pour l'unicité. Le moyen le plus court que je connais pour le faire est en Perl:
Notez les
\W
ancres supplémentaires pour vous assurer que seuls les mots de 10 caractères exactement correspondent.la source
D'autres ont suggéré que cela n'est pas possible sans diverses extensions de certains systèmes d'expression régulière qui ne sont en fait pas réguliers. Cependant, comme la langue que vous souhaitez associer est finie, elle est clairement régulière. Pour 3 lettres d'un alphabet à 4 lettres, ce serait facile:
De toute évidence, cela devient incontrôlable avec plus de lettres et des alphabets plus grands. :-)
la source
Option
--perl-regexp
(courte-P
) de GNUgrep
utilise des expressions régulières plus puissantes qui incluent des modèles d'anticipation. Le modèle suivant recherche pour chaque lettre que cette lettre n'apparaît pas dans le reste du mot:Cependant, le comportement au moment de l'exécution est assez mauvais, car il
\w*
peut avoir une longueur presque infinie. Il peut être limité à\w{,8}
, mais cela vérifie également au-delà de la limite de 10 lettres. Par conséquent, le modèle suivant vérifie d'abord la longueur de mot correcte:En tant que fichier de test, j'ai utilisé un gros fichier de 500 Mo:
Mise à jour:
Je n'ai pas pu trouver de changement significatif dans le comportement à l'exécution pour un opérateur non gourmand (
\w*?
) ou un opérateur possessif ((...){10}+
). Un tout petit peu plus rapide semble le remplacement de l'option-w
:Une mise à jour de grep de la version 2.13 à 2.18 était beaucoup plus efficace. Le fichier de test n'a pris que ≈ 6 s.
la source
\w{,8}?
) aidait pour certains types d'entrées (mais pas de manière très significative). Belle utilisation de\g{-1}
pour contourner le bogue de grep GNU.\g{-1}
, car elle rend le motif plus indépendant de l'emplacement. Sous cette forme, il peut être utilisé dans le cadre d'un modèle plus large.Une solution Perl:
mais ça ne marche pas avec
ou
testé avec perl v5.14.2 et v5.18.2
la source