views:

710

answers:

3

Can anyone provide an algorithm to validate a Singaporean FIN?

I know with a Singaporean NRIC I can validate it via modulo 11 and then compare the result to a lookup table but cannot find a similar lookup table for the FIN.

I also do not know for sure if the modulo 11 is the correct method to validate.

I am aware the government sells a algorithm for $400 but maybe someone knows a cheaper way.

Bonus points for c# implementation.

A: 

After a little searching around I found a way to validate them. This doesn't neccersarily mean the FIN is valid, just that it falls within a valid range.

I based it on algorithms from http://www.ngiam.net/NRIC/ppframe.htm

I've also included a similar method for checking NRIC because I figure anyone who comes across this and is interested in one is interested in the other as well.

Hope this helps someone!

 private static readonly int[] Multiples = { 2, 7, 6, 5, 4, 3, 2 };

 public static bool IsNricValid(string nric)
 {
  if (string.IsNullOrEmpty(nric))
  {
   return false;
  }

  // check length
  if (nric.Length != 9)
  {
   return false;
  }

  int total = 0
   , count = 0
   , numericNric;
  char first = nric[0]
   , last = nric[nric.Length - 1];

  if (first != 'S' && first != 'T')
  {
   return false;
  }

  if (!int.TryParse(nric.Substring(1, nric.Length - 2), out numericNric))
  {
   return false;
  }

  while (numericNric != 0)
  {
   total += numericNric % 10 * Multiples[Multiples.Length - (1 + count++)];

   numericNric /= 10;
  }

  char[] outputs;
  if (first == 'S')
  {
   outputs = new char[] { 'J', 'Z', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A' };
  }
  else
  {
   outputs = new char[] { 'G', 'F', 'E', 'D', 'C', 'B', 'A', 'J', 'Z', 'I', 'H' };
  }

  return last == outputs[total % 11];

 }

 public static bool IsFinValid(string fin)
 {
  if (string.IsNullOrEmpty(fin))
  {
   return false;
  }

  // check length
  if (fin.Length != 9)
  {
   return false;
  }

  int total = 0
   , count = 0
   , numericNric;
  char first = fin[0]
   , last = fin[fin.Length - 1];

  if (first != 'F' && first != 'G')
  {
   return false;
  }

  if (!int.TryParse(fin.Substring(1, fin.Length - 2), out numericNric))
  {
   return false;
  }

  while (numericNric != 0)
  {
   total += numericNric % 10 * Multiples[Multiples.Length - (1 + count++)];

   numericNric /= 10;
  }

  char[] outputs;
  if (first == 'F')
  {
   outputs = new char[] { 'X', 'W', 'U', 'T', 'R', 'Q', 'P', 'N', 'M', 'L', 'K' };
  }
  else
  {
   outputs = new char[] { 'R', 'Q', 'P', 'N', 'M', 'L', 'K', 'X', 'W', 'U', 'T' };
  }

  return last == outputs[total % 11];
 }
marshall
A: 

Here's similar code written in JavaScript

var nric = [];

nric.multiples = [ 2, 7, 6, 5, 4, 3, 2 ];

nric.isNricValid = function (theNric) {

    if (!theNric || theNric == '')
    {
        return false;
    }

    if (theNric.length != 9)
    {
        return false;
    }

    var total = 0
        , count = 0
        , numericNric;
    var first = theNric[0]
        , last = theNric[theNric.length - 1];

    if (first != 'S' && first != 'T')
    {
        return false;
    }

    numericNric = theNric.substr(1, theNric.length - 2);

    if (isNaN(numericNric)) {
        return false
    }

    while (numericNric != 0)
    {
        total += (numericNric % 10) * nric.multiples[nric.multiples.length - (1 + count++)];

        numericNric /= 10;
        numericNric = Math.floor(numericNric);
    }

    var outputs;
    if (first == 'S')
    {
        outputs = [ 'J', 'Z', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A' ];
    }
    else
    {
        outputs = [ 'G', 'F', 'E', 'D', 'C', 'B', 'A', 'J', 'Z', 'I', 'H' ];
    }

    return last == outputs[total % 11];

}

nric.isFinValid = function(fin)
{
    if (!fin || fin == '')
    {
        return false;
    }

    if (fin.length != 9)
    {
        return false;
    }

    var total = 0
        , count = 0
        , numericNric;
    var first = fin[0]
        , last = fin[fin.length - 1];

    if (first != 'F' && first != 'G')
    {
        return false;
    }

   numericNric = fin.substr(1, fin.length - 2);

    if (isNaN(numericNric)) {
        return false;
    }

    while (numericNric != 0)
    {
        total += (numericNric % 10) * nric.multiples[nric.multiples.length - (1 + count++)];

        numericNric /= 10;
        numericNric = Math.floor(numericNric);
    }

    var outputs;
    if (first == 'F')
    {
        outputs = [ 'X', 'W', 'U', 'T', 'R', 'Q', 'P', 'N', 'M', 'L', 'K' ];
    }
    else
    {
        outputs = [ 'R', 'Q', 'P', 'N', 'M', 'L', 'K', 'X', 'W', 'U', 'T' ];
    }

    return last == outputs[total % 11];
}
marshall
A: 

And again in PHP

function isNricValid ($theNric) {

    $multiples = array( 2, 7, 6, 5, 4, 3, 2 );

    if (!$theNric || $theNric == '')
    {
        return false;
    }

    if (strlen($theNric) != 9)
    {
        return false;
    }

    $total = 0;
    $count = 0;
    $numericNric = 0;

    $first = $theNric[0];
    $last = $theNric[strlen($theNric) - 1];

    if ($first != 'S' && $first != 'T')
    {
        return false;
    }

    $numericNric = substr($theNric, 1, strlen($theNric) - 2);

    if (!is_numeric ($numericNric)) {
        return false;
    }

    while ($numericNric != 0)
    {
        $total += ($numericNric % 10) * $multiples[sizeof($multiples) - (1 + $count++)];

        $numericNric /= 10;
        $numericNric = floor($numericNric);
    }

    $outputs = '';
    if (strcmp($first, "S") == 0)
    {
        $outputs = array( 'J', 'Z', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A' );
    }
    else
    {   
        $outputs = array( 'G', 'F', 'E', 'D', 'C', 'B', 'A', 'J', 'Z', 'I', 'H' );
    }

    return $last == $outputs[$total % 11];

}

function isFinValid ($fin)
{
    $multiples = array( 2, 7, 6, 5, 4, 3, 2 );
    if (!$fin || $fin == '')
    {
        return false;
    }

    if (strlen($fin) != 9)
    {
        return false;
    }

    $total = 0;
    $count = 0;
    $numericNric = 0;
    $first = $fin[0];
    $last = $fin[strlen($fin) - 1];

    if ($first != 'F' && $first != 'G')
    {
        return false;
    }

    $numericNric = substr($fin, 1, strlen($fin) - 2);

    if (!is_numeric ($numericNric)) {
        return false;
    }

    while ($numericNric != 0)
    {
        $total += ($numericNric % 10) * $multiples[sizeof($multiples) - (1 + $count++)];

        $numericNric /= 10;
        $numericNric = floor($numericNric);
    }

    $outputs = array();

    if (strcmp($first, 'F') == 0)
    {
        $outputs = array( 'X', 'W', 'U', 'T', 'R', 'Q', 'P', 'N', 'M', 'L', 'K' );
    }
    else
    {
        $outputs = array( 'R', 'Q', 'P', 'N', 'M', 'L', 'K', 'X', 'W', 'U', 'T' );
    }

    return $last == $outputs[$total % 11];
}
marshall