Sunday, May 31, 2015

Validate Indian PAN Using Go Regular Expression

PAN (Permanent Account Number) is a unique 10 character alpha-numeric code issued by Indian Income Tax Department. It's a credit card size card issued with the basic details of the entity (individual, company, trust, firm etc.) and the 10 character code printed on it. A PAN is mandatory for majority of financial transactions.

Note: The code in this article will do only a basic validation by pattern matching to rule out the junk entries. It CAN NOT be used to verify if the PAN code entered is genuine.

Do You Want to Test the Code in Action in Your Browser?
  • Before going through the entire article, would you like to check this code in action? Visit the page, click run and follow the prompt.
PAN Card Format and Rules
  1. 10 character alpha-numeric.
  2. AAAPL1234C: First five characters are letters, next four numerals, last character letter.
  3. The 1st 3 letters are sequnce of alphabets from AAA to ZZZ
  4. The 4th character informs - Type of holder of card:
                         A — Association of Persons (AOP)
                         B — Body of Individuals (BOI)
                         C — Company
                         F — Firm
                         G — Government
                         H — HUF (Hindu Undivided Family)
                         L — Local Authority
                         J — Artificial Judicial Person
                         P — Individual
                         T — AOP (Trust)

    5. The 5th character is an Alphabet [A to Z]
    6. The 10th or last character is an alphabet.

Validate Using Regular Expression (Regex)

Regex is a sequence of characters that define a search pattern, mainly for use in pattern matching with strings. To understand the code, beginners must pay attention to the comment blocks in below code snippet.


package main

import (
 "fmt"
 "regexp"
 "strings"
)

func main() {
 /*
    For details http://www.golangpro.com/2015/05/validate-indian-pan-using-go-regular-expression.html
 */

 fmt.Println("Enter PAN code")
 var pan string
 fmt.Scanf("%s", &pan)
 //The string entered is converted to upper case
 pan = strings.ToUpper(pan)
 fmt.Println("You entered: ", pan)
 /*
    Regular Expression
    1. import regexp package
    2. ^ indicates "at the beginning of string"
    3. $ indicates "at the end of string"
    4. [A-Z] indicates any upper case alphabet from A to Z both inclusive
    5. {3} exactly 3
    6. [0-9] indiates any numeric between 0 & 9 both inclusive
 */

 re := regexp.MustCompile("^[A-Z]{3}[ABCFGHLJPT]{1}[A-Z]{1}[0-9]{4}[A-Z]{1}$")

 var t, msg string

 //If the pattern doesn't match MatchString will return "false"

 if !re.MatchString(pan) {
  msg = "PAN format is invalid"

 } else {

  //It's a valid PAN, Let us check the 4th character to find Type of Holder
  panType := pan[3:4]

  switch panType {
  case "A":
      t = "Association of Persons (AOP)"
  case "B":
      t = "Body of Individuals (BOI)"
  case "C":
      t = "Company"
  case "F":
      t = "Firm"
  case "G":
      t = "Government"
  case "H":
      t = "HUF (Hindu Undivided Family)"
  case "L":
      t = "Local Authority"
  case "J":
      t = "Artificial Judicial Person"
  case "P":
      t = "Individual"
  case "T":
      t = "AOP (Trust)"
  }
  fmt.Println("PAN is valid; type of holder of PAN card: ", t)
 }
 fmt.Println(msg)
}



Output
What Next?

Play with the code here

Learn more about RegExp syntax

We can write a function that takes PAN as input parameter and returns the valid or invalid message to the calling function.

Is the code written above idiomatic Go? I'm learning, appreciate if you can share your feedback to improve the code. Spread the word if you like this :)



Saturday, May 9, 2015

Golang Maps with Examples for Beginners

Go provides built-in collection types like Slices & Maps. Maps are un-ordered collection of key-value pairs. In other 
languages a Map is known with names such as dictionaries, hash table, associative array etc. In the adjoining image here, we have a table that stores Key and Value pair


What are the values for key B?

  
By looking at the above image (table) you can easily derive that there are two set of values Name & Example. For key B the corresponding values are Name = Blue & Example = Sky. In a Map, values (data) can be retrieved very fast by providing the corresponding key.

At the end of this post we'll see how we can represent the above image (table) with the help of a Map.


Declare a Map
var color map[string]string

This should be read as the variable color is a map of string keys to string values.

A Map declaration should follow the below format:

var <name-of-the map> map[keyDataType]ValueDataType

Where as keyDataType = string, int, float. [i.e. Types where == operation works]

Initialize a Map
color := make(map[string]string)

Use of make function ensures that memory is allocated for the Map named color as Maps are Reference Types.

The above looks similar to simple Arrays with a little difference that Maps are dynamic in nature i.e. new items can be added to it. Another difference is that unlike Arrays which are sequential, Maps are NOT sequential.

The above declaration is rewritten below with an added second argument that defines initial capacity of the Map. In below declaration 3 is the initial capacity (Size) of the Map named color
                               color := make(map[string]string, 3)
Gopher Tip

The capacity of a map doesn't have to be known at creation. But for performance reasons, it is a good practice to specify the capacity even if it's an approximate number.

Remember: Maps are reference types. Note: The Gopher Tip image is an adaptation of Renee French's Go Gopher Mascot

Example Code

Here's a simple code example of Go Maps:

Code Snippet RefCode# Map 1.1
package main
import "fmt"
func main() {    
color := make(map[string]string)    

 color["R"] = "Red"    
 color["B"] = "Blue"   
 color["G"] = "Green"    

 fmt.Println(color["B"])
} 

Play with the above code here.
Output RefCode# Map 1.1
Blue
OK. That was quite simple. Now, let us modify the above code to get the user's favorite color as an input.
Code Snippet RefCode# Map 1.2
package main
import "fmt"
func main() {    
color := make(map[string]string)    

 color["R"] = "Red"    
 color["B"] = "Blue"   
 color["G"] = "Green"    

 fmt.Println("Select a Primary Color: R / B / G")
 var colorCode string
 fmt.Scanf("%s", &colorCode)
 
 if value, isOK := color[colorCode]; isOK {
 fmt.Println("You love " +value) } else {
    fmt.Println("Invalid entry OR Key not found in our record")
   }
} 


Code Explanation RefCode# Map 1.2

Here Scanf function from the fmt package is used to read the user's input.

We can see from RefCode# Map 1.2 that  only 3 key-value pairs: R, B, G (case sensitive) are present in the Map. 
  • What happens if a user enters any other key except R,B or G? 
  • How to check the existence of a a key?
This check is performed using the following construct, with 2 variables, namel value and isOK:

if value, isOK := color[colorCode]; isOK {

             //some code
}

isOK returns a Boolean value true only if the key is present in the Map else it returns false

The other variable value contains the actual value/data of the corresponding key of the Map.
As shown in the below output image, if after executing the above code I enter the key as R: It returns You love Red If you enter g as key; isOK will return false as we don't have any value corresponding to the key g (case sensitive).  G will retrieve a valid data as shown below.
Play with the RefCode# Map 1.2
Output RefCode# Map 1.2
Here's a succinct way to rewrite the code snippet RefCode# Map 1.2
Code Snippet RefCode# Map 1.3
package main
import "fmt"
func main() {    
color := map[string]string{    

        "R": "Red",  //Did you notice the comma?
        "B": "Blue",   
        "G": "Green",    
}
 fmt.Println("Select a Primary Color: R / B / G")
 var colorCode string
 fmt.Scanf("%s", &colorCode)
 
 if _, isOK := color[colorCode]; isOK {
 fmt.Println("You love " +color[colorCode]) } else {
    fmt.Println("Invalid entry OR Key not found in our record")
   }
}

Let us see an example of a Map where we have more than one named values/data for a single key.

Code Snippet RefCode# Map 1.4

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main
import "fmt"
func main() {    
color := map[string]map[string]string{    

        "R": map[string]string{
           "name":"Red",  //Note the double quote in name, value
           "example":"Cherry",
        },
           
        "B": map[string]string{
           "name":"Blue",  
           "example":"Sky",
        }, 
        
       "G": map[string]string{
           "name":"Green",  
           "example":"Grass",
        },    
}
     fmt.Println("Select a Primary Color: R / B / G")
     var colorCode string
     fmt.Scanf("%s", &colorCode)
 
     if value, isOK := color[colorCode]; isOK {
       fmt.Println("You love " +value["name"] +" "+ value["example"]) 
     } else {
          fmt.Println("Invalid entry OR Key not found in our record")
     }
}
Output RefCode# Map 1.4
You can play with Code Snippet RefCode# Map 1.4

Please share if you liked it.