Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercices][confirmé] carte bancaire

Anonyme
4 juillet 2010 à 12:42:25

Vérifier la somme de contrôle d'une carte bancaire. Pour cela vous devrez vérifier qu'un numéro de carte bancaire respecte l'algorithme de Luhn pour les sommes de contrôle.

Résultat : mardi soir

Merci de votre participation

Mon code en version 2.6

def verifCarteValide(num_carte):
    """Vérifie que le numéro de carte satisafait une somme de contrôle luhn mod-10."""

    somme=0
    nb_chiffres=len(num_carte)
    impair_pair=nb_chiffres & 1
    for compteur in range(nb_chiffres):
        chiffre=int(num_carte[compteur])
        if not ((compteur & 1) ^ impair_pair):
            chiffre=chiffre*2
        if chiffre > 9:
            chiffre=chiffre - 9
        somme+=chiffre
    return (somme%10)==0
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 14:55:24

Une horreur, desole...
nombre = '8763'
n = len(nombre)
i = 0

while n > 0:
    n -= 1
    i += int(nombre[n])
    if n - 1 < 0:
        continue
    else:
        n -= 1
        if int(nombre[n])*2 > 9:
            i += int(nombre[n])*2-9
        else:
            i += int(nombre[n])*2

if i%10 == 0:
    print('Code bon.')
else:
    print('Code errone.')

>>>  Code bon.

J'avoue avoir pris plus de temps que je ne le pensais, et je pensais egalement reussir a faire un code plus digeste ; car il est assez simple a comprendre cet algo.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 15:11:56

Petite aide, pour trouver un nombre pair

>>> 12 & 1
0
>>> 5 & 1
1


Ca simplifiera ton programme enfin je l'espère
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 15:23:06

Je ne vois pas.
Peux-tu preciser en quoi ca pourrais m'aider ?
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 15:28:04

1.on démarre avec le dernier chiffre (à droite) et on se déplace vers la gauche, en doublant la valeur de tous les chiffres de rang pair : le dernier est traité en 1er, il n'est pas doublé, l'avant-dernier (2e) sera doublé. Si le double d'un chiffre dépasse 10, on le remplace par la somme de ses chiffres. Par exemple, 1 111 devient 2 121, tandis que 8 763 devient 7 733 (car 2×6=12, et 1+2=3 ; 2×8=16, et 1+6=7).
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 16:30:11

On ne traite que des nombres a 4 chiffres ?
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 16:32:20

Non c'est un seystème utilisé pour les numéros de cartes bancaire
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 16:38:31

Lecureuil tu as une erreur dans ton code (seulement le décalage des nombres à multiplier par deux).
Au temps pour moi, c'est moi qui me suis trompé de sens.

Voici ma version en une ligne de code avec un syntaxe très compréhensible, ... :)

def luhn(nbr):
    return sum([int(n) if i % 2 == 0 % 2 else int(n) * 2 if int(n) * 2 < 10 else int(n) * 2 - 9 for i, n in enumerate(reversed(str(nbr)))]) % 10 == 0


  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 16:53:44

ca ne fonctionne pas, j'ai testé avec ma carte
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 16:54:57

Mais alors Fred, ca va changer en fonction du nombre donne par len().
972487086 => Le premier chiffre a multiplier sera de rang impair (7).
3256 => Pair (2).

(Je sens que je dis n'importe quoi).
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 16:58:10

Citation : fred1599

ca ne fonctionne pas, j'ai testé avec ma carte



Je viens de tester avec ma carte et j'avais aussi tester avec l'exemple de Wiki et ça fonctionne.
De plus mon programme suit bien l'algo.

Edit : J'ai tester avec une autre carte (avec le programme et aussi à la main) et je trouve que le numéro ne correspond pas.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 17:06:15

Ca ne fonctionne toujours pas avec ma carte, mais en effet avec l'exemple du wiki ca fonctionne. Cependant mon code fonctionne avec ma carte, l'exemple du wiki et je suis sûr la tienne :p
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 17:33:24

Hmm j'ai trouvé mon erreur. En fait, je multipliais par deux dans le mauvais sens (de gauche à droite au lieu de droite à gauche).

Domage que ma carte ET l'exemple soit valide dans un sens comme dans l'autre ^^.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 17:56:26

Ton problème est donc résolu ;)
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 18:04:43

Citation : EPonix

Lecureuil tu as une erreur dans ton code (seulement le décalage des nombres à multiplier par deux).
Au temps pour moi, c'est moi qui me suis trompé de sens.

Voici ma version en une ligne de code avec un syntaxe très compréhensible, ... :)


def luhn(nbr):
    return sum([int(n) if i % 2 == 0 % 2 else int(n) * 2 if int(n) * 2 < 10 else int(n) * 2 - 9 for i, n in enumerate(reversed(str(nbr)))]) % 10 == 0




C'est typiquement le genre de choses à ne pas faire pour des raisons de lisibilité et d'efficacité.
Il serait plus intéressant de coder une version accessible à tous, en étalant autant que nécessaire le code pour avoir une structure impérative qui parle plus au débutant.
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 18:19:12

Je sais très bien que ce n'est pas lisible et qu'il vaut mieux developper plus. Pourtant je préfère largement les codes la.

Voici une version que j'aurais fait sans vouloir faire à tout prix une seule ligne :

def luhn(nbr):
    lsPair = [int(n) for i, n in enumerate(reversed(str(nbr))) if i % 2 == 0]
    lsImpair = [int(n) * 2 for i, n in enumerate(reversed(str(nbr))) if i % 2 == 1]
    lsImpair1 = [_ for _ in lsImpair if _ < 10]
    lsImpair2 = [_ - 9 for _ in lsImpair if _ >= 10]
    
    return (sum(lsPair) + sum(lsImpair1) + sum(lsImpair2) % 10 == 0



C'est un outil puissant de python qui reste assez clair pour être utilisé par les débutants.
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 18:32:27

Un petit essai vite fait :
def valide(num_carte):
    paire = False
    res = 0
    for a in reversed(num_carte):
        c = int(a)
        if paire:
            c *= 2
            if c >= 10:
                res -= 9
        res += c
        paire = not paire
    return (res%10 == 0)
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 20:28:17

Un premier jet :
#[Exercices][confirmé] carte bancaire

def luhn(n) :
  som = 0
  o = 0 
  for i in reversed(n) :
    o += 1
    if o % 2 == 0 :
      if (int(i)*2)>9 :
        som += int(i)*2 - 9
      else :
        som += int(i)*2
    else :
      som += int(i)
  return (som%10) == 0

y = input("code carte : ")
print(luhn(x))

Je me suis certainement compliqué la vie.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
4 juillet 2010 à 20:41:01

print(luhn(x))


pas x mais y
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 20:55:39

Bon, j'ai voulu m'amuser un peu :
valide = lambda s : sum([int(n) if int(n) < 10 else int(n[0]) + int(n[1]) for n in [str(int(n) * (1 + i % 2)) for (i, n) in (enumerate(s[::-1]))][::-1]]) % 10 == 0

>>> valide("1111")
False
>>> valide("8763")
True


Il faut donner le nombre en chaîne de caractère, mais au pire il suffirait de rajouter des str(n) pour l'avoir en int.
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 23:36:02

Citation : fred1599

Petite aide, pour trouver un nombre pair

>>> 12 & 1
0
>>> 5 & 1
1




Non, je ne rêve pas.

Citation : fred1599

def verifCarteValide(num_carte):
    """Vérifie que le numéro de carte satisafait une somme de contrôle luhn mod-10."""

    somme=0
    nb_chiffres=len(num_carte)
    impair_pair=nb_chiffres & 1
    for compteur in range(nb_chiffres):
        chiffre=int(num_carte[compteur])
        if not ((compteur & 1) ^ impair_pair):
            chiffre=chiffre*2
        if chiffre > 9:
            chiffre=chiffre - 9
        somme+=chiffre
    return (somme%10)==0


Je crois pas que tu aies compris à quoi servent les opérateurs bit à bit enfin là on a affaire à une caricature d'utilisation.
nb_chiffres & 1 est identique à nb_chiffres %2 . De même, si a et b sont parmi 0 ou 1, a^b est identique à a or b

En outre, je trouve ton astuce pour éviter de mettre à l'envers (ou pour ne pas partir directement de la droite) est très artificielle et nuit à la lisibilité. Faut quand même que les débutants sachent que ce n'est vraiment pas comme ça qu'il faut faire. Il y a un principe en Python qui dit :

Readability counts.



Autre méthode, pas très lisible si on ne connait pas mais qui correspond plus ou moins à ce qu'on fait à la main quand on applique l'algorithme (j'évite les lambda qui n'apportent rien) :


def g(s):
    return sum([int(x) for x in s[-1::-2]] + [2 * int(x) if int(x)< 5 else 2 * int(x) - 9 for x in s[-2::-2]]) % 10 == 0

print g('48951313')

(Python 2.6)

True


[Au passage, l'algo est très vite et bien expliqué ici]

L'idée est juste d'extraire via des slices ([truc : machin : bidule] ) les parties de la chaîne sur lesquelles on veut travailler :

>>> s
'48951313'
>>> # Les termes de rangs impairs à partir de la droite
... s[-1::-2]
'3358'
>>> # Les termes de rangs pairs à partir de la droite
... s[-2::-2]
'1194'
>>>







  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 23:43:10

Citation

j'évite les lambda qui n'apportent rien



En python, quand on veut écrire le truc le plus concis possible, c'est ça qu'on utilise en général. Et pour le coup, le fait d'écrire le def sur la ligne précédente n'apporte rien, vu que l'objectif de ce genre de code est d'écrire tout en une ligne. Ça n'est pas PEP 8, mais c'est le jeu. Le lambda permet éventuellement d'appliquer aussi la fonction dans la même ligne.
  • Partager sur Facebook
  • Partager sur Twitter
4 juillet 2010 à 23:49:00

Algorithme de Wikipédia :
function checkLuhn(string purportedCC) : boolean {
     int sum := 0
     int nDigits := length(purportedCC)
     int parity := nDigits AND 1
     for i from nDigits-1 to 0 {
         int digit := integer(purportedCC[i])
         if (i AND 1) = parity
             digit := digit × 2
         if digit > 9
             digit := digit - 9 
         sum := sum + digit
     }
     return (sum % 10) = 0
 }


Il suffit de mettre la syntaxe Python à la place de celle ci pour obtenir le code de fred1599 j'ai l'impression.
  • Partager sur Facebook
  • Partager sur Twitter
5 juillet 2010 à 0:55:16

Citation : Maxibolt


En python, quand on veut écrire le truc le plus concis possible, c'est ça qu'on utilise en général.



Ce qui compte plutôt c'est que le code de la fonction soit le plus concis possible, après l'enveloppe, c'est la cerise sur le gâteau. Et au bout du compte, tu gagnes juste un saut de ligne, bof, bof, bof. Et tu en en arrives d'ailleurs à la situation presque grotesque où tu dois nommer une fonction anonyme !!


Citation : Maxibolt


Et pour le coup, le fait d'écrire le def sur la ligne précédente n'apporte rien, vu que l'objectif de ce genre de code est d'écrire tout en une ligne.


Une fois de plus l'intérêt est réduit, vaut mieux se concentrer sur le code de la fonction, avec le meilleur rapport concision/lisibilité, et franchement, je n'ai pas trouvé que c'était très réussi dans ton code.

Citation : EPonix

Algorithme de Wikipédia :

function checkLuhn(string purportedCC) : boolean {
     int sum := 0
     int nDigits := length(purportedCC)
     int parity := nDigits AND 1
     for i from nDigits-1 to 0 {
         int digit := integer(purportedCC[i])
         if (i AND 1) = parity
             digit := digit × 2
         if digit > 9
             digit := digit - 9 
         sum := sum + digit
     }
     return (sum % 10) = 0
 }



Il suffit de mettre la syntaxe Python à la place de celle ci pour obtenir le code de fred1599 j'ai l'impression.



Oui, c'est étrangement proche. En outre, cet algorithme contient une maladresse puisque la ligne 10 n'est atteinte que si digit a été doubl et donc que le test de la ligne 7 est passé. Par suite, une fois sur deux la ligne 9 est testé inutilement. Il fallait donc écrire plutôt :


function checkLuhn(string purportedCC) : boolean {
     int sum := 0
     int nDigits := length(purportedCC)
     int parity := nDigits AND 1
     for i from nDigits-1 to 0 {
         int digit := integer(purportedCC[i])
         if (i AND 1) = parity
             digit := digit × 2
             if digit > 9
                 digit := digit - 9 
         sum := sum + digit
     }
     return (sum % 10) = 0
 }


[cette remarque vaut pour le code du PO ...]

De toute façon, ce code ne me paraît naturel, en ce sens qu'il ne colle pas assez près à la description informelle de l'algorithme qui consiste à dire :
je parcours ma chaine depuis la droite, chiffre par chiffre :
si le chiffe a une position impaire (position à l'extrême droite = 1), on l'ajoute à la somme courante
sinon, il y a deux cas :
-- si le chiffre c est < 5 on ajoute 2*c à la somme courante
-- sinon, on ajoute 2*c-9 à la somme courante.

Cela étant dit, cette description donne le code suivant :


def f(num):
    s = 0
    n = len(num)
    for k in range(n):
        z = int(num[(n - 1) - k])
        if k % 2 == 0:
            s += z
        elif z < 5:
            s += 2 * z
        else:
            s += 2 * z - 9
    return s


print  f("972487086")


50


suivant l'exemple donné dans Wikipedia.
  • Partager sur Facebook
  • Partager sur Twitter
5 juillet 2010 à 10:37:46

Citation

Ce qui compte plutôt c'est que le code de la fonction soit le plus concis possible, après l'enveloppe, c'est la cerise sur le gâteau. Et au bout du compte, tu gagnes juste un saut de ligne, bof, bof, bof. Et tu en en arrives d'ailleurs à la situation presque grotesque où tu dois nommer une fonction anonyme !!



"lambda" peut servir pour définir une fonction anonyme, mais ce n'est pas non plus "le mot clé des fonctions anonymes". On s'en sert très souvent pour définir une fonction en une seule ligne, où il est alors préférable à def.
Et dans le genre de code que j'ai écrit, le but n'est absolument pas de faire un truc lisible, mais uniquement de s'amuser à écrire en une ligne ce qui prend 12 lignes dans un code normal. Le lambda est alors une sorte de règle tacite : on fait toujours comme ça (parce que finalement, l'uniligne avec def n'en est pas vraiment un : c'est plutôt deux lignes collées).

Citation

Une fois de plus l'intérêt est réduit, vaut mieux se concentrer sur le code de la fonction, avec le meilleur rapport concision/lisibilité, et franchement, je n'ai pas trouvé que c'était très réussi dans ton code.


Normal, ce n'était absolument pas l'objectif. Si je devais vraiment coder cette fonction, je ne ferais jamais comme ça, mais plutôt effectivement en transcrivant l'algo de wikipedia en Python (ou quelque chose du style). Mais en Python propre, pas comme celui que tu proposes : la boucle for sert à itérer directement sur la chaîne, on ne l'utilise pas pour faire varier l'indice de la boucle de 0 à la longueur de la chaîne moins un. Si on veut vraiment se servir de cet indice, on utilise enumerate. Ce que tu as fait est valide, mais absolument pas pythonnique :

def luhn(num):
    s = 0
    for (indice, chiffre) in enumerate(num[::-1]):
        z = int(chiffre)
        if indice % 2 == 0:
            s += z
        elif z < 5:
            s += 2 * z
        else:
            s += 2 * z - 9
    return s


print  luhn("972487086")


Si on ne veut pas utiliser [::-1], on peut toujours utiliser les méthodes spéciales des listes. Jouer avec les n - k est un peu moche, et correspond un peu à "faire du C, mais en Python".


edit : tiens, d'ailleurs, si on veut éviter le triple if :
for i in xrange(19):
        print i, i / 10 + i % 10

  • Partager sur Facebook
  • Partager sur Twitter
5 juillet 2010 à 11:48:41

Les codes qui tiennent en une ligne, c'est de la factorisation ? Vous avez un lien ou autre svp ?
  • Partager sur Facebook
  • Partager sur Twitter
5 juillet 2010 à 11:51:30

C'est surtout des codes qu'on écrit "pour s'amuser".
  • Partager sur Facebook
  • Partager sur Twitter
5 juillet 2010 à 14:48:40

L'astuce est surtout d'utiliser des expressions le plus possible. On se retrouve avec moins d'instructions et donc de lignes et ça permet de faire des trucs illisibles comme ça:

from random import randrange
main = (lambda nbm=randrange(0,1001),info= "Tapez un nombre entier compris entre 0 et 1000", coup=0: main(info=([False,"Plus petit !!","Plus grand !!"][cmp(input(info),nbm)]),coup=coup+1) if info else raw_input("Vous avez gagné en %d coups" % coup))
main()

(C'est un plus ou moins en trois lignes).
  • Partager sur Facebook
  • Partager sur Twitter
5 octobre 2010 à 16:03:40

Bonjour,

Je ressors le topic des ténèbres du forum Python ;)
Mon code bidouillé:

chaine = "8763"
liste = []
z = []
var = 0

for i in chaine:
        i = int(i)
            
        if i%2 == 0:
            liste.append(str(i*2))
        else:
            liste.append(str(i))
#liste: ['16', '7', '12', '3']

for elem in liste:
    
    if int(elem) >= 10:
        for j in elem:
            var += int(j)
        z.append(var)
        var = 0 
    else:
        z.append(int(elem))
#z: [7, 7, 3, 3]

for i in z:
    var += i:
if var % 10 == 0:
    print("Le code est bon")
#Le code est bon


Bonne journée,
Realmagma
  • Partager sur Facebook
  • Partager sur Twitter