How to validate a CPF using a function in R?

Asked

Viewed 577 times

4

I am trying to improve the code of @Rui Barradas that is posted here as a response, but it does not work for some situations. After debugging the code, I understand that the problem lies in the function cpf_validar, since the cpf_dig_controle works well, even entering 9 digits and, the cpf_gerar for me is "ok". I have already worked on some lines, but I did not succeed. If someone can give some contribution:

# gerar digito de controle a partir de 8 digitos
cpf_dig_controle <- function(y){
v1 <- 0L
v2 <- 0L
z <- as.integer(rev(strsplit(as.character(y), "")[[1]]))
for(i in seq_along(z)){
v1 <- v1 + z[i]*(9 - (i %% 10))
v2 <- v2 + z[i]*(9 - ((i + 1) %% 10))
}
v1 <- (v1 %% 11) %% 10
v2 <- v2 + v1*9
v2 <- (v2 %% 11) %% 10
c(v1, v2)
}

# gerar CPF
cpf_gerar <- function(x){
g <- function(y, v){
z <- strsplit(as.character(y), "")[[1]]
z <- as.integer(c(z, v))
res <- sprintf(fmt = "%d%d%d.%d%d%d.%d%d%d-%02d",
               z[1], z[2], z[3], z[4], z[5],
               z[6], z[7], z[8], z[9], z[10])
res
}
v <- lapply(x, cpf_dig_controle)
result <- sapply(seq_along(x), function(i) g(x[i], v[[i]]))
result
}

# cpf gerado
cpf <- cpf_gerar(c("01861932", "01234567","12345678","11511611"))
cpf

# validar cpf
cpf_validar <- function(x){
f <- function(y){
z <- unlist(strsplit(y, "\\."))
v <- substr(z[3], 3, 6)
v <- as.integer(unlist(strsplit(v, "-")))
z[3] <- substr(z[3], 1, 2)
z <- as.integer(paste(z, collapse = ""))
list(x = z, v = v)
}
result <- lapply(x, f)
valido <- lapply(result, function(r) unlist(lapply(r$x, 
cpf_dig_controle)))
valido <- sapply(seq_along(valido), function(i)
result[[i]]$v[1] == valido[[i]][1] & result[[i]]$v[2] == valido[[i]][2]
)
valido
}

#cpfs gerados pela função cpf_dig_controle a partir de 8 digitos
cpf_validar(c("018.619.323-00","012.345.673-02","123.456.786- 
02","115.116.111-04"))

#cpf válido, porém a função o qualifica como FALSE
cpf_validar("288.065.030-57")
  • The function cpf_gerar(28806503) with the first 8 digits of the CPF you use as valid in the last row provides a different CPF than you are using: "288.065.035-07". The question now is how do you make sure that the CPF you are using is valid?

  • Rafael, good morning. I tried to validate my own CPF and my eaposa with the function CPF validate and the answer was FALSE. I did the test of the veesifier digit using its digit checker function for the CPF mentioned above and the digits were entered correctly. Also I did several other tests uaando Cpfs generated by Devs. For this reason I believe that the problwma is in CPF validate function. I tried to adjust it, but the knowledge that poaauo hj was not enough for it to succeed. If you could make a contribution it would be of great value. Thank you

  • Carlos, running the functions, I noticed that the checkers digits generated by the function cpf_dig_controle are not going to the last two CPF values in function cpf_gerar. The first digit after the trace of this function is always 0 (at least every time I surround it), so there may be a problem in the function cpf_gerar

1 answer

3

I made changes to the three functions created by @Rui Barradas in this post.

I modified the algorithm generating the check digits since when I put my CPF, the generated values did not match. The new algorithm I used was that website.

cpf_dig_controle <- function(y){
 v1 <- 0L
  v2 <- 0L
  num <- is.numeric(y)
  z <- as.integer(strsplit(as.character(y), "")[[1]])
  n <- length(z)
  if(num){
    if(n == 7){
      z <- c(0, z, sample(0:9, 1))
    } else{
      if(n == 8){
        z <- c(0, z)
      } else{
        z <- z
      }
    }
  } else{
    if(n == 8){
      z <- c(z, sample(0:9, 1))
    } else{
      z <- z
    }
  }
  for(i in seq_along(z)){
    v1 <- v1 + z[i]*(11-i)
    v2 <- v2 + z[i]*(12-i)
  }
  v1 <- v1 %% 11
  if(v1 < 2){
    v1 <- 0
  } else{
    v1 <- 11 - v1
  }
  v2 <- v2 + 2*v1
  v2 <- v2 %% 11
  if(v2 < 2){
    v2 <- 0
  } else{
    v2 <- 11 - v2
  }
  c(v1, v2)
}

I changed the function cpf_gerar because the same always put the number 0 as the first after the dash (-) in the CPF.

 cpf_gerar <- function(x){
   g <- function(y, v){
     num <- is.numeric(y)
     z <- as.integer(strsplit(as.character(y), "")[[1]])
     n <- length(z)
     if(num){
       if(n == 7){
         z <- c(0, z, sample(0:9, 1))
       } else{
         if(n == 8){
           z <- c(0, z)
         } else{
           z <- z
         }
       }
     } else{
       if(n == 8){
         z <- c(z, sample(0:9, 1))
       } else{
         z <- z
       }
     }
     z <- as.integer(c(z, v))
     res <- sprintf(fmt = "%d%d%d.%d%d%d.%d%d%d-%d%d",
                    z[1], z[2], z[3], z[4], z[5], z[6], z[7], z[8], z[9], z[10], z[11])
     res
   }
   v <- lapply(x, cpf_dig_controle)
   result <- sapply(seq_along(x), function(i) g(x[i], v[[i]]))
   result
 }

Finally, I took into account the changes made in the two functions above to modify the cpf_validar.

cpf_validar <- function(x){
  f <- function(y){
    z <- unlist(strsplit(y, "\\."))
    v <- substr(z[3], 5, 6)
    v <- as.integer(unlist(strsplit(v, "")))
    z[3] <- substr(z[3], 1, 3)
    z <- as.integer(paste(z, collapse = ""))
    list(x = z, v = v)
  }
  result <- lapply(x, f)
  valido <- lapply(result, function(r) unlist(lapply(r$x, cpf_dig_controle)))
  valido <- sapply(seq_along(valido), function(i)
    result[[i]]$v[1] == valido[[i]][1] & result[[i]]$v[2] == valido[[i]][2]
  )
  valido
}

When performing the test with Cpf’s that you are sure are valid and were giving FALSE in the old functions and after changes to validate the 0 as first digit, I get:

cpf_validar("288.065.030-57")
[1] TRUE

cpf_gerar("018619326")
[1] "018.619.326-26"
cpf_gerar(018619326)
[1] "018.619.326-26"
cpf_validar("018.619.326-26")
[1] TRUE

cpf_gerar("012345678")
[1] "012.345.678-90"
cpf_gerar(012345678)
[1] "012.345.678-90"
cpf_validar("012.345.678-90")
[1] TRUE
  • Rafael, good afternoon.

  • I did some tests in the adjusted code is validating more valid Cpf now, but in my tests Cpf have zero start, has presented problems. Behold:

  • > cpf_generate("018619326") [1] "018.619.326-26" > cpf_validate("018.619.326-26") [1] FALSE

  • > cpf_generate("012345678") [1] "012.345.678-90" > # TEST > cpf_validate("012.345.678-90") [1] FALSE

  • Carlos, these cases are falling into the problem I reported when the initial digit is 0 and I didn’t have time to try to get around it. For now I’ll owe you

  • 1

    @CARLOSPHERE I think I’ve managed to get around the problems you were encountering.

  • When you can publish the code, please. I believe it will be very useful for many people. Abs

  • I’ve already updated my answer.

  • good evening and good Sunday.

  • My friend, has improved a lot.... is almost perfect. The function validate CPF is only failing with Cpfs starting with 2 zeros. From what I’ve tested, the problem lies in generating digits. When I try to generate the digit checker starting with two zeros it ignores one and applies the algorithm to the others, this way it ends up calculating wrong. Follow the results:

  • cpf_validate("243.442.940-84")#test ok cpf_validate("001.647.550-04") #test failed cpf_validate("009.421.270-80")# test failed cpf_validate("769.926.630-70")# test ok cpf_validate("067.093.890-49")#test ok cpf_validate("099.890.090-74")#test ok cpf_validate("#("867.759.820-03")#test ok cpf_validate("360.890.880-30")#test ok cpf_validate("020.031.234-07")#test ok cpf_validate("060.284.457-62")#test ok

  • It’s pretty tricky working with zero left. I was able to circumvent when the CPF contains only 1 and I didn’t think about the case of 2. Maybe an output is to include in the functions an argument that indicates if there is (and how many are) zero left.

Show 7 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.