Validation for 4 digit pin

Hi,

 I have requirement to validate 4-digit pin. Below are the requirement of the 4-digit number

1. pin should not allow sequential numbers

2.  pin should not allow same numbers

example: 1234 or 4321 or 0000, 1111 or 4444 or 2222 or 3333 numbers are not allowed as a card pin.

can anyone please help me how to write logic for the validation.

thanks in advance!

  Discussion posts and replies are publicly visible

  • +1
    Certified Lead Developer

    A first idea here. Not sure if it catches all edge cases.

    a!localVariables(
      local!pins: {"7369", "1234", "4321", "0000", "1111", "4444", "2222", "3333"},
      a!forEach(
        items: local!pins,
        expression: and(
          fv!item <> concat(tointeger(left(fv!item, 1)) + enumerate(4)), /* positive sequence */
          fv!item <> concat(tointeger(left(fv!item, 1)) + enumerate(4) * -1), /* negative sequence */
          fv!item <> rept(mid(fv!item, 1, 1), 4), /* 4 times the first character */
          fv!item <> rept(mid(fv!item, 2, 1), 4), /* 4 times the second character */
          fv!item <> rept(mid(fv!item, 3, 1), 4), /* 4 times the third character */
          fv!item <> rept(mid(fv!item, 4, 1), 4) /* 4 times the fourth character */
        )
      )
    )

  • 0
    Certified Senior Developer

    Hi ,

    Please try the below code. Here rule input (ri!pin) is of type text

     

    if(
      and(
        len(ri!pin)=4,
        len(tostring(tointeger(ri!pin)))=len(ri!pin)
      ),
      a!localVariables(
        local!numbersUsed:{
          int(charat(ri!pin,1)),
          int(charat(ri!pin,2)),
          int(charat(ri!pin,3)),
          int(charat(ri!pin,4))
        },
        if(
          length(union(local!numbersUsed,local!numbersUsed))<>length(local!numbersUsed),
          "numbers cannot be repeated in pin",
          if(
            and(
              local!numbersUsed[1]+1=local!numbersUsed[2],
              local!numbersUsed[2]+1=local!numbersUsed[3],
              local!numbersUsed[3]+1=local!numbersUsed[4],
            ),
            "cannot be sequentail numbers",
            "no error"
          )
        )
      ),
      "pin should be 4 characters and should contain only numbers"
    )

  • 0
    Certified Senior Developer

    a!localVariables(
    local!a:regexmatch(
    pattern:"^(?!.*?(?:012|123|234|345|456|567|678|789|987|876|765|654|543|432|321|210|(\d)\1\1))\d{4}$",
    searchString:9989,
    regexFlags:"gms"
    ),
    local!a
    )

    Hi , can you check the above code by placing in expression rule working fine for me .
    if you don't find regexmatch() in your rule , then add "Regular expression functions" plugin

  • Hi, 
    Here is a solution which covers all edge cases. (Some humble bragging)
    The expression rule 'isPinValid' provides an array as a result. 
    The first item in the result is a Boolean indicating if the Pin is valid, the second item in the result is the validation message

    a!localVariables(
      /* Checks if the pin is compliant to the rules: has 4 digits, no sequences (ascending or descending) and not the same 4 digits */
      /* Get the digits of the pin - ri!pin is in text format */
      local!allDigits: tostring(ri!pin), 
      local!count: len(local!allDigits),
      local!digits: a!forEach(items: enumerate(local!count),expression: tointeger(local!allDigits[fv!index])),
      /* Prep for the sequence test, calculating the difference between the digits - ldrop is for the edge case if the pin starts with a 1 */
      local!seq:ldrop({0,local!digits} - {local!digits,0},1),
      /* Same digits? */
      local!sd: if(1=length(union(local!digits,local!digits)),true,false),
      /* Check if we have a sequence of numbers e. g. 2345 or 8765 */
      local!seq1: if(3<=length(wherecontains(-1,local!seq)),true,false),
      local!seq2: if(3<=length(wherecontains(1,local!seq)),true,false),
      /* Is the pin valid (true), or is one of the rules violated? (false) */
      local!check: not(or(4<>local!count,local!sd,local!seq1,local!seq2)),
       { 
        local!check,
        /* Providing the confirmation and/or error message  */
        a!match(value:true,
        whenTrue: count(local!digits)<>length(local!digits),
        then: "Pin can only contain Digits",
        whenTrue: local!check,
        then: "Pin is valid",
        whentrue:4<>local!count,
        then: "Pin has not 4 digits",
        whentrue: local!sd,
        then: "Pin can't have the same 4 digits",
        whenTrue: or(local!seq1,local!seq2),
        then: "Pin can't have digits in " & if(local!seq1,"a","de") & "cending sequence",
        default: "Not a valid pin"
        )
      }
    )