Imports System.Linq.Expressions
Imports System.Text.RegularExpressions
'''
''' Representa un número. En la clase se desglosan las distintas opciones que se puedan
''' encontrar
'''
Public Class ValidarDocumentoIdentidad
'''
''' Tipos de Códigos.
'''
''' Aunque actualmente no se utilice el término CIF, se usa en la enumeración
''' por comodidad
Public Enum TiposDocumentosEnum
NIF
NIE
CIF
End Enum
' Número tal cual lo introduce el usuario
Private m_numero As String
Private tipo As TiposDocumentosEnum
Public ReadOnly Property TipoDocumento As TiposDocumentosEnum
Get
Return tipo
End Get
End Property
'''
''' Parte de Nif: En caso de ser un Nif intracomunitario, permite obtener el cógido del país
'''
Public Property CodigoIntracomunitario() As String
Get
Return m_CodigoIntracomunitario
End Get
Friend Set(value As String)
m_CodigoIntracomunitario = value
End Set
End Property
Private m_CodigoIntracomunitario As String
Friend Property EsIntraComunitario() As Boolean
Get
Return m_EsIntraComunitario
End Get
Set(value As Boolean)
m_EsIntraComunitario = value
End Set
End Property
Private m_EsIntraComunitario As Boolean
'''
''' Parte de Nif: Letra inicial del Nif, en caso de tenerla
'''
Public Property LetraInicial() As String
Get
Return m_LetraInicial
End Get
Friend Set(value As String)
m_LetraInicial = value
End Set
End Property
Private m_LetraInicial As String
'''
''' Parte de Nif: Bloque numérico del NIF. En el caso de un NIF de persona física,
''' corresponderá al DNI
'''
Public Property Identificador() As Integer
Get
Return m_numero
End Get
Friend Set(value As Integer)
m_numero = value
End Set
End Property
Private m_Identificador As Integer
'''
''' Parte de Nif: Dígito de control. Puede ser número o letra
'''
Public Property DigitoControl() As String
Get
Return m_DigitoControl
End Get
Friend Set(value As String)
m_DigitoControl = value
End Set
End Property
Private m_DigitoControl As String
'''
''' Valor que representa si el Nif introducido es correcto
'''
Public Property EsCorrecto() As Boolean
Get
Return m_EsCorrecto
End Get
Friend Set(value As Boolean)
m_EsCorrecto = value
End Set
End Property
Private m_EsCorrecto As Boolean
'''
''' Cadena que representa el tipo de Nif comprobado:
''' - NIF : Número de identificación fiscal de persona física
''' - NIE : Número de identificación fiscal extranjería
''' - CIF : Código de identificación fiscal (Entidad jurídica)
'''
Public ReadOnly Property TipoNif() As String
Get
Return tipo.ToString()
End Get
End Property
'''
''' Constructor. Al instanciar la clase se realizan todos los cálculos
'''
''' Cadena de 9 u 11 caracteres que contiene el DNI/NIF
''' tal cual lo ha introducido el usuario para su verificación
Public Sub New(numero As String)
' Se eliminan los carácteres sobrantes
Try
numero = EliminaCaracteres(numero)
numero = numero.ToUpper()
' Comprobación básica de la cadena introducida por el usuario
If numero.Length <> 9 AndAlso numero.Length <> 11 Then
Me.EsCorrecto = False ' Throw New ArgumentException("El NIF no tiene un número de caracteres válidos")
Else
Me.m_numero = numero
Desglosa()
Select Case tipo
Case TiposDocumentosEnum.NIF, TiposDocumentosEnum.NIE
Me.EsCorrecto = CompruebaNif()
Exit Select
Case TiposDocumentosEnum.CIF
Me.EsCorrecto = validateCif(numero)
' Me.EsCorrecto = CompruebaCif()
Exit Select
End Select
End If
Catch ex As Exception
Me.EsCorrecto = False
End Try
End Sub
#Region "Preparación del número (desglose)"
'''
''' Realiza un desglose del número introducido por el usuario en las propiedades
''' de la clase
'''
Private Sub Desglosa()
Dim n As Int32
If m_numero.Length = 11 Then
' Nif Intracomunitario
EsIntraComunitario = True
CodigoIntracomunitario = m_numero.Substring(0, 2)
LetraInicial = m_numero.Substring(2, 1)
Int32.TryParse(m_numero.Substring(3, 7), n)
DigitoControl = m_numero.Substring(10, 1)
tipo = GetTipoDocumento(LetraInicial(0))
Else
' Nif español
tipo = GetTipoDocumento(m_numero(0))
EsIntraComunitario = False
If tipo = TiposDocumentosEnum.NIF Then
LetraInicial = String.Empty
Int32.TryParse(m_numero.Substring(0, 8), n)
Else
LetraInicial = m_numero.Substring(0, 1)
Dim listaLetrasNIE As Char() = {"X", "Y", "Z"}
If listaLetrasNIE.Contains(LetraInicial) Then
'// Las letras por las que comienza el NIE deben ser reemplazadas por números antes de realizar
'// la operación Int32.TryParse, que además deberá incluir ese número reemplazado.
'// X = 0
'// Y = 1
'// Z = 2
Select Case LetraInicial
Case "X"
m_numero = 0 & m_numero.Substring(1, m_numero.Length - 1)
Case "Y"
m_numero = 1 & m_numero.Substring(1, m_numero.Length - 1)
Case "Z"
m_numero = 2 & m_numero.Substring(1, m_numero.Length - 1)
End Select
Int32.TryParse(m_numero.Substring(0, 8), n)
Else
'// El curso normal, cuando la letra inicial no es X, Y o Z.
Int32.TryParse(m_numero.Substring(1, 7), n)
End If
End If
DigitoControl = m_numero.Substring(8, 1)
End If
Identificador = n
End Sub
'''
''' En base al primer carácter del código, se obtiene el tipo de documento que se intenta
''' comprobar
'''
''' Primer carácter del número pasado
''' Tipo de documento
Private Function GetTipoDocumento(letra As Char) As TiposDocumentosEnum
Dim regexIdentificadors As New Regex("[0-9]")
If regexIdentificadors.IsMatch(letra.ToString()) Then
Return TiposDocumentosEnum.NIF
End If
Dim regexLetrasNIE As New Regex("[LKMXYZ]")
If regexLetrasNIE.IsMatch(letra.ToString()) Then
Return TiposDocumentosEnum.NIE
End If
Dim regexLetrasCIF As New Regex("[ABCDEFGHJPQRSUVNW]")
If regexLetrasCIF.IsMatch(letra.ToString()) Then
Return TiposDocumentosEnum.CIF
End If
Throw New ApplicationException("El código no es reconocible")
End Function
'''
''' Eliminación de todos los carácteres no numéricos o de texto de la cadena
'''
''' Número tal cual lo escribe el usuario
''' Cadena de 9 u 11 carácteres sin signos
Private Function EliminaCaracteres(numero As String) As String
' Todos los carácteres que no sean números o letras
Dim caracteres As String = "[^\w]"
Dim regex As New Regex(caracteres)
Return regex.Replace(numero, "")
End Function
#End Region
#Region "Cálculos"
Private Function CompruebaNif() As Boolean
Return DigitoControl = GetLetraNif()
End Function
Public Shared Function validateCif(ByVal cif As String) As Boolean
If String.IsNullOrEmpty(cif) Then Return False
cif = cif.Trim().ToUpper()
If cif.Length <> 9 Then Return False
Dim firstChar As String = cif.Substring(0, 1)
Dim cadena As String = "ABCDEFGHJNPQRSUVW"
If cadena.IndexOf(firstChar) = -1 Then Return False
Try
Dim sumaPar As Int32 = Nothing
Dim sumaImpar As Int32 = Nothing
Dim cif_sinControl As String = cif.Substring(0, 8)
Dim digits As String = cif_sinControl.Substring(1, 7)
For n As Int32 = 0 To digits.Length - 1 Step 2
If n < 6 Then
sumaPar += Convert.ToInt32(digits(n + 1).ToString())
End If
Dim dobleImpar As Int32 = 2 * Convert.ToInt32(digits(n).ToString())
sumaImpar += (dobleImpar Mod 10) + (dobleImpar \ 10)
Next
Dim sumaTotal As Int32 = sumaPar + sumaImpar
sumaTotal = (10 - (sumaTotal Mod 10)) Mod 10
Dim digitoControl As String = ""
Select Case firstChar
Case "N", "P", "Q", "R", "S", "W"
Dim characters As Char() = {"J"c, "A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c}
digitoControl = characters(sumaTotal).ToString()
Case Else
digitoControl = sumaTotal.ToString()
End Select
Return digitoControl.Equals(cif.Substring(8, 1))
Catch __unusedException1__ As Exception
Return False
End Try
End Function
'''
''' Cálculos para la comprobación del Cif (Entidad jurídica)
'''
'Private Function CompruebaCif() As Boolean
' Dim letrasCodigo As String() = {"J", "A", "B", "C", "D", "E", _
' "F", "G", "H", "I"}
' Dim n As String = Identificador.ToString()
' Dim sumaPares As Int32 = 0
' Dim sumaImpares As Int32 = 0
' Dim sumaTotal As Int32 = 0
' Dim i As Int32 = 0
' Dim digitoCalculado As String
' Dim retVal As Boolean = False
' ' Recorrido por todos los dígitos del número
' For i = 0 To n.Length - 1
' Dim aux As Int32
' Int32.TryParse(n(i).ToString(), aux)
' If (i + 1) Mod 2 = 0 Then
' ' Si es una posición par, se suman los dígitos
' sumaPares += aux
' Else
' ' Si es una posición impar, se multiplican los dígitos por 2
' aux = aux * 2
' ' se suman los dígitos de la suma
' sumaImpares += SumaDigitos(aux)
' End If
' Next
' ' Se suman los resultados de los números pares e impares
' sumaTotal += sumaPares + sumaImpares
' ' Se obtiene el dígito de las unidades
' Dim unidades As Int32 = sumaTotal Mod 10
' ' Si las unidades son distintas de 0, se restan de 10
' If unidades <> 0 Then
' unidades = 10 - unidades
' End If
' Select Case LetraInicial
' ' Sólo números
' Case "A", "B", "E", "H"
' retVal = DigitoControl = unidades.ToString()
' Exit Select
' ' Sólo letras
' Case "K", "P", "Q", "S"
' retVal = DigitoControl = letrasCodigo(unidades)
' Exit Select
' Case Else
' retVal = (DigitoControl = unidades.ToString()) OrElse (DigitoControl = letrasCodigo(unidades))
' Exit Select
' End Select
' Return retVal
'End Function
'''
''' Obtiene la suma de todos los dígitos
'''
''' de 23, devuelve la suma de 2 + 3
Private Function SumaDigitos(digitos As Int32) As Int32
Dim sIdentificador As String = digitos.ToString()
Dim suma As Int32 = 0
For i As Int32 = 0 To sIdentificador.Length - 1
Dim aux As Int32
Int32.TryParse(sIdentificador(i).ToString(), aux)
suma += aux
Next
Return suma
End Function
'''
''' Obtiene la letra correspondiente al Dni
'''
Private Function GetLetraNif() As String
Dim indice As Integer = Identificador Mod 23
Return "TRWAGMYFPDXBNJZSQVHLCKET"(indice).ToString()
End Function
'''
''' Obtiene una cadena con el número de identificación completo
'''
Public Overrides Function ToString() As String
Dim nif As String
nif = If(EsIntraComunitario, CodigoIntracomunitario, Convert.ToString(String.Empty + LetraInicial & Identificador) & DigitoControl)
Return nif
End Function
#End Region
'''
''' Comprobación de un número de identificación fiscal español
'''
''' Identificador a analizar
''' Instancia de con los datos del número.
''' Destacable la propiedad , que contiene la verificación
'''
Public Shared Function CompruebaNif(numero As String) As ValidarDocumentoIdentidad
Return New ValidarDocumentoIdentidad(numero)
End Function
End Class