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