associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

Diferenças para "VerificadorDeCpf"

Diferenças entre as versões de 1 e 10 (9 versões de distância)
Revisão 1e 2003-11-16 18:23:39
Tamanho: 3162
Editor: PedroWerneck
Comentário:
Revisão 10e 2008-09-26 14:05:50
Tamanho: 4545
Editor: localhost
Comentário: converted to 1.6 markup
Deleções são marcadas assim. Adições são marcadas assim.
Linha 1: Linha 1:
#pragma section-numbers off
Linha 4: Linha 3:
Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados. Além de útil, também é um bom exemplo de como otimizar código que lida com manipulação de números e strings, usando as funções reduce(), map() e ''list compreensions''. Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados.

Ver
também: VerificadorDeCpfCnpjSimples.
Linha 7: Linha 8:
Linha 14: Linha 16:
def _gen(cpf):
    """Gera o próximo dígito do número de CPF
"""
Linha 17: Linha 18:
    """
    res = []
    for i in range(len(cpf)):
        a = cpf[i]
        b = (len(cpf) + 1 - i)
        res.append(b * a)

    res = reduce(int.__add__, res) % 11

    if res > 1:
        return (11 - res)
    else:
        return 0
Este módulo fornece uma classe wrapper para ser usada com números de
CPF, que além de oferecer um método simples de verificação, também
conta com métodos para comparação e conversão.
Linha 32: Linha 23:
def _translate(cpf):
    """Traduz o número como string na forma:
>>> a = CPF('56068332551')
>>> b = CPF('560.683.325-51')
>>> c = CPF((1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0))
>>> assert a.valido()
>>> assert b.valido()
>>> assert not c.valido()
>>> assert a == b
>>> assert not b == c
>>> assert not a == c
>>> assert eval(repr(a)) == a
>>> assert eval(repr(b)) == b
>>> assert eval(repr(c)) == c
>>> assert str(a) == \"560.683.325-51\"
>>> assert str(b) == str(a)
>>> assert str(c) == \"123.456.789-00\"
Linha 35: Linha 39:
    123.456.789-10 """
Linha 37: Linha 41:
    para a forma:

    12345678910

    """
    
    i = xrange(256)
    t = [' '] * 256
    e = ''.join([chr(x) for x in i if not chr(x).isdigit()])
    
    for x in i:
        if chr(x).isdigit():
            t[x] = chr(x)
            
    return cpf.translate(''.join(t), e)
Linha 57: Linha 46:
    _gen = staticmethod(_gen)
    _translate = staticmethod(_translate)
    
Linha 61: Linha 47:
        """O argumento cpf pode ser uma string nas formas:         """Classe representando um número de CPF
Linha 63: Linha 49:
        12345678910
        123.456.789-10

        ou uma lista ou tuple
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]
        (1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0)
        >>> a = CPF('95524361503')
        >>> b = CPF('955.243.615-03')
        >>> c = CPF([9, 5, 5, 2, 4, 3, 6, 1, 5, 0, 3])
Linha 71: Linha 54:
        
        try:
            basestring
        except:
            basestring = (str, unicode)
Linha 73: Linha 61:
            cpf = cpf.replace(".", "")
            cpf = cpf.replace("-", "")
Linha 74: Linha 64:
               cpf = self._translate(cpf)                 raise ValueError("Valor não segue a forma xxx.xxx.xxx-xx")
Linha 76: Linha 66:
        self.cpf = [int(x) for x in cpf]         if len(cpf) < 11:
            raise ValueError("O número de CPF deve ter 11 digítos")

        self.cpf = map(int, cpf)
Linha 81: Linha 75:
        >>> a = CPF('95524361503')
        >>> a[9] == '0'
        True
        >>> a[10] == '3'
        True
        >>> a[9] == 0
        False
        >>> a[10] == 3
        False
Linha 82: Linha 86:
          return self.cpf[index]         return str(self.cpf[index])
Linha 89: Linha 92:

        >>> a = CPF('95524361503')
        >>> print repr(a)
        CPF('95524361503')
        >>> eval(repr(a)) == a
        True
Linha 91: Linha 100:
        
Linha 97: Linha 105:
        >>> a = CPF('95524361503')
        >>> b = CPF('955.243.615-03')
        >>> c = CPF('123.456.789-00')
        >>> a == b
        True
        >>> a != c
        True
        >>> b != c
        True
Linha 98: Linha 116:
Linha 104: Linha 121:
        """Retorna uma representação do CPF na forma:         """Retorna uma string do CPF na forma com pontos e traço
Linha 106: Linha 123:
        123.456.789-10         >>> a = CPF('95524361503')
        >>> str(a)
        '955.243.615-03'
        
Linha 109: Linha 129:

d = iter("..-")
        d = ((3, "."), (7, "."), (11, "-"))
Linha 112: Linha 131:
        for i in xrange(3, 12, 4):
            s.insert(i, d.next())
        for i, v in d:
            s.insert(i, v)
Linha 117: Linha 136:
    def isValid(self):     def valido(self):
Linha 120: Linha 139:
        >>> a = CPF('95524361503')
        >>> a.valido()
        True
        >>> b = CPF('12345678900')
        >>> b.valido()
        False
Linha 121: Linha 147:
        cpf = self.cpf[:9]
        # pegamos apenas os 9 primeiros dígitos do cpf e geramos os
        # dois dígitos que faltam
        while len(cpf) < 11:

            r = sum(map(lambda(i,v):(len(cpf)+1-i)*v,enumerate(cpf))) % 11

            if r > 1:
                f = 11 - r
            else:
                f = 0
            cpf.append(f)

        # se o número com os digítos faltantes coincidir com o número
        # original, então ele é válido
        return bool(cpf == self.cpf)

    def __nonzero__(self):
        """Valida o número de cpf
Linha 122: Linha 167:
        s = self.cpf[:9]
        s.append(self._gen(s))
        s.append(self._gen(s))
        return s == self.cpf[:]
        >>> a = CPF('95524361503')
        >>> bool(a)
        True
        >>> b = CPF('12345678900')
        >>> bool(b)
        False
        >>> if a:
        ... print 'OK'
        ...
        OK
Linha 127: Linha 178:
}}}         >>> if b:
        ... print 'OK'
        ...
        >>>
        """

        return self.valido()
Linha 131: Linha 188:
== Exemplo de uso == if __name__ == "__main__":
Linha 133: Linha 190:
{{{
#!python
#/usr/bin/env python
# -*- coding:UTF-8 -*-


from cpf import CPF

# Estes números foram gerados aleatoriamente :)

VALIDO = "113.451.253-80"
INVALIDO = "31354110274"

# qualquer um dos dois formatos (com pontos ou não) pode ser usado

valido = CPF(VALIDO)
invalido = CPF(INVALIDO)

assert valido.verificar()
assert not invalido.verificar()
    import doctest, sys
    doctest.testmod(sys.modules[__name__])
Linha 161: Linha 199:
Pedro Werneck PedroWerneck

Receita: Verificador de CPF

Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados.

Ver também: VerificadorDeCpfCnpjSimples.

Código

   1 #/usr/bin/env python
   2 # -*- coding:UTF-8 -*-
   3 
   4 
   5 """
   6 
   7 Este módulo fornece uma classe wrapper para ser usada com números de
   8 CPF, que além de oferecer um método simples de verificação, também
   9 conta com métodos para comparação e conversão.
  10 
  11 
  12 >>> a = CPF('56068332551')
  13 >>> b = CPF('560.683.325-51')
  14 >>> c = CPF((1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0))
  15 >>> assert a.valido()
  16 >>> assert b.valido()
  17 >>> assert not c.valido()
  18 >>> assert a == b
  19 >>> assert not b == c
  20 >>> assert not a == c
  21 >>> assert eval(repr(a)) == a
  22 >>> assert eval(repr(b)) == b
  23 >>> assert eval(repr(c)) == c
  24 >>> assert str(a) == \"560.683.325-51\"
  25 >>> assert str(b) == str(a)
  26 >>> assert str(c) == \"123.456.789-00\"
  27 
  28 """
  29 
  30 
  31 
  32 
  33 class CPF(object):
  34 
  35     def __init__(self, cpf):
  36         """Classe representando um número de CPF
  37 
  38         >>> a = CPF('95524361503')
  39         >>> b = CPF('955.243.615-03')
  40         >>> c = CPF([9, 5, 5, 2, 4, 3, 6, 1, 5, 0, 3])
  41 
  42         """
  43 
  44         try:
  45             basestring
  46         except:
  47             basestring = (str, unicode)
  48 
  49         if isinstance(cpf, basestring):
  50             cpf = cpf.replace(".", "")
  51             cpf = cpf.replace("-", "")
  52             if not cpf.isdigit():
  53                 raise ValueError("Valor não segue a forma xxx.xxx.xxx-xx")
  54             
  55         if len(cpf) < 11:
  56             raise ValueError("O número de CPF deve ter 11 digítos")
  57 
  58         self.cpf = map(int, cpf)
  59 
  60 
  61     def __getitem__(self, index):
  62         """Retorna o dígito em index como string
  63 
  64         >>> a = CPF('95524361503')
  65         >>> a[9] == '0'
  66         True
  67         >>> a[10] == '3'
  68         True
  69         >>> a[9] == 0
  70         False
  71         >>> a[10] == 3
  72         False
  73 
  74         """
  75         return str(self.cpf[index])
  76 
  77     def __repr__(self):
  78         """Retorna uma representação 'real', ou seja:
  79 
  80         eval(repr(cpf)) == cpf
  81 
  82         >>> a = CPF('95524361503')
  83         >>> print repr(a)
  84         CPF('95524361503')
  85         >>> eval(repr(a)) == a
  86         True
  87         
  88         """
  89         return "CPF('%s')" % ''.join([str(x) for x in self.cpf])
  90 
  91     def __eq__(self, other):
  92         """Provê teste de igualdade para números de CPF
  93 
  94         >>> a = CPF('95524361503')
  95         >>> b = CPF('955.243.615-03')
  96         >>> c = CPF('123.456.789-00')
  97         >>> a == b
  98         True
  99         >>> a != c
 100         True
 101         >>> b != c
 102         True
 103 
 104         """
 105         if isinstance(other, CPF):
 106             return self.cpf == other.cpf
 107         return False
 108     
 109     def __str__(self):
 110         """Retorna uma string do CPF na forma com pontos e traço
 111 
 112         >>> a = CPF('95524361503')
 113         >>> str(a)
 114         '955.243.615-03'
 115         
 116 
 117         """
 118         d = ((3, "."), (7, "."), (11, "-"))
 119         s = map(str, self.cpf)
 120         for i, v in d:
 121             s.insert(i, v)
 122         r = ''.join(s)
 123         return r
 124 
 125     def valido(self):
 126         """Valida o número de cpf
 127 
 128         >>> a = CPF('95524361503')
 129         >>> a.valido()
 130         True
 131         >>> b = CPF('12345678900')
 132         >>> b.valido()
 133         False
 134 
 135         """
 136         cpf = self.cpf[:9]
 137         # pegamos apenas os 9 primeiros dígitos do cpf e geramos os
 138         # dois dígitos que faltam
 139         while len(cpf) < 11:
 140 
 141             r = sum(map(lambda(i,v):(len(cpf)+1-i)*v,enumerate(cpf))) % 11
 142 
 143             if r > 1:
 144                 f = 11 - r
 145             else:
 146                 f = 0
 147             cpf.append(f)
 148 
 149         # se o número com os digítos faltantes coincidir com o número
 150         # original, então ele é válido
 151         return bool(cpf == self.cpf)
 152 
 153     def __nonzero__(self):
 154         """Valida o número de cpf
 155         
 156         >>> a = CPF('95524361503')
 157         >>> bool(a)
 158         True
 159         >>> b = CPF('12345678900')
 160         >>> bool(b)
 161         False
 162         >>> if a:
 163         ...     print 'OK'
 164         ... 
 165         OK
 166 
 167         >>> if b:
 168         ...     print 'OK'
 169         ... 
 170         >>>
 171         """
 172 
 173         return self.valido()
 174 
 175 
 176 
 177 if __name__ == "__main__":
 178 
 179     import doctest, sys
 180     doctest.testmod(sys.modules[__name__])

Volta para CookBook.


PedroWerneck