J'ai trouvé l'exemple de code suivant pour Java sur RosettaCode :
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
- Je ne connais pas Java en particulier mais je comprends tous les aspects de cet extrait de code à l'exception de l'expression régulière elle-même
- J'ai des connaissances de base à avancées de Regex telles que vous les trouvez dans les fonctions PHP intégrées
Comment faire .?|(..+?)\\1+
correspondre les nombres premiers?
!new String(new char[n]).matches(".?|(..+?)\\1+")
équivaut à!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.Réponses:
Vous avez dit que vous comprenez cette partie, mais juste pour souligner, la chaîne générée a une longueur égale au nombre fourni. La chaîne comporte donc trois caractères si et seulement si
n == 3
.La première partie de l'expression régulière dit "n'importe quel caractère, zéro ou une fois". Donc , fondamentalement, est là zéro ou un character-- ou, par ce que je l' ai mentionné ci - dessus,
n == 0 || n == 1
. Si nous avons la correspondance, retournez la négation de cela. Cela correspond au fait que zéro et un ne sont PAS premiers.La deuxième partie de l'expression régulière est un peu plus délicate, s'appuyant sur des groupes et des références arrière. Un groupe est tout ce qui est entre parenthèses, qui sera ensuite capturé et stocké par le moteur regex pour une utilisation ultérieure. Une référence arrière est un groupe apparié qui est utilisé plus tard dans la même expression régulière.
Le groupe capture 1 personnage, puis 1 ou plus de n'importe quel personnage. (Le caractère + signifie un ou plusieurs, mais UNIQUEMENT du caractère ou du groupe précédent. Donc ce n'est pas "deux ou quatre ou six caractères etc.", mais plutôt "deux ou trois etc." Le +? Est comme +, mais il essaie de faire correspondre le moins de caractères possible. + essaie normalement d'avaler toute la chaîne s'il le peut, ce qui est mauvais dans ce cas car cela empêche la partie de référence de fonctionner.)
La partie suivante est la référence arrière: ce même jeu de caractères (deux ou plus), qui apparaît à nouveau. Ladite référence arrière apparaît une ou plusieurs fois.
Alors. Le groupe capturé correspond à un nombre naturel de caractères (à partir de 2) capturés. Ledit groupe apparaît alors un certain nombre naturel de fois (également à partir de 2). S'il y a une correspondance, cela implique qu'il est possible de trouver un produit de deux nombres supérieurs ou égaux à 2 qui correspondent à la chaîne de longueur n ... ce qui signifie que vous avez un n composé. Encore une fois, retournez la négation de la correspondance réussie: n n'est PAS premier.
Si aucune correspondance ne peut être trouvée, alors vous ne pouvez pas trouver votre produit de deux nombres naturels supérieurs ou égaux à 2 ... et vous avez à la fois une non-correspondance et un nombre premier, d'où à nouveau le retour de la négation du résultat du match.
Le voyez-vous maintenant? C'est incroyablement délicat (et coûteux en calcul!) Mais c'est aussi assez simple en même temps, une fois que vous l'avez compris. :-)
Je peux élaborer si vous avez d'autres questions, comme sur le fonctionnement réel de l'analyse des regex. Mais j'essaie de garder cette réponse simple pour le moment (ou aussi simple que possible).
la source
J'expliquerai la partie regex en dehors des tests de primalité: la regex suivante, étant donné une
String s
qui consiste à répéterString t
, trouvet
.La façon dont cela fonctionne est que l'expression régulière capture
(.*)
dans\1
, puis voit s'il y a une\1+
suite. L'utilisation de^
et$
garantit qu'une correspondance doit concerner la chaîne entière.Donc, d'une certaine manière, on nous donne
String s
, qui est un "multiple" deString t
, et l'expression rationnelle le trouverat
(le plus long possible, car il\1
est gourmand).Une fois que vous avez compris pourquoi cette expression régulière fonctionne, alors (en ignorant la première alternative dans l'expression régulière d'OP pour le moment) expliquer comment elle est utilisée pour les tests de primalité est simple.
n
, commencez par générer unString
de longueurn
(rempli avec le mêmechar
)String
d'une longueur (disonsk
) dans\1
, et essaie de correspondre\1+
au resteString
n
est un multiple propre dek
, etn
n'est donc pas premier.k
qui divisen
, etn
est donc unEn fait, ce n'est pas le cas! Il correspond
String
dont la longueur n'est PAS prime!.?
: La première partie de l'alternance correspond à laString
longueur0
ou1
(PAS prime par définition)(..+?)\1+
: La deuxième partie de l'alternance, une variation de l'expression rationnelle expliquée ci-dessus, correspond à uneString
longueurn
qui est "un multiple" de aString
de longueurk >= 2
(c'estn
-à- dire est un composite, PAS un premier).?
n'est en fait pas nécessaire pour l'exactitude, mais il peut aider à accélérer le processus en essayant d'k
abord plus petitNotez l'
!
boolean
opérateur complément dans l'return
instruction: il annule lematches
. C'est quand le regex NE correspond PAS ,n
c'est primordial! C'est une logique double négative, donc pas étonnant que ce soit un peu déroutant !!Simplification
Voici une simple réécriture du code pour le rendre plus lisible:
Ce qui précède est essentiellement le même que le code Java d'origine, mais divisé en plusieurs instructions avec des affectations à des variables locales pour rendre la logique plus facile à comprendre.
Nous pouvons également simplifier l'expression rationnelle, en utilisant la répétition finie, comme suit:
Encore une fois, étant donné une
String
longueurn
, remplie de la même chosechar
,.{0,1}
vérifie sin = 0,1
, PAS amorcer(.{2,})\1+
vérifie sin
est un multiple correct dek >= 2
, PAS primeÀ l'exception du modificateur réticent
?
sur\1
(omis pour plus de clarté), l'expression rationnelle ci - dessus est identique à l'original.Plus de regex amusant
L'expression régulière suivante utilise une technique similaire; il doit être éducatif:
Voir également
la source
[Populist]
peu de temps.Belle astuce regex (bien que très inefficace) ... :)
L'expression régulière définit les non-nombres premiers comme suit:
N n'est pas premier si et seulement si N <= 1 OU N est divisible par un K> 1.
Au lieu de passer la simple représentation numérique de N au moteur d'expression régulière, il est alimenté par une séquence de longueur N, composée d'un caractère répétitif. La première partie de la disjonction vérifie N = 0 ou N = 1, et la seconde recherche un diviseur K> 1, en utilisant des références arrière. Cela force le moteur de regex à trouver une sous-séquence non vide qui peut être répétée au moins deux fois afin de former la séquence. Si une telle sous-séquence existe, cela signifie que sa longueur divise N, donc N n'est pas premier.
la source
Appliquer aux nombres après conversion en base 1 (1 = 1, 2 = 11, 3 = 111, ...). Les non-nombres premiers correspondront à cela. Si cela ne correspond pas, c'est le premier.
Explication ici .
la source