What is the RegEx to test for a compliant FATCA Global Intermediary Identification Number (GIIN)?

Viewed 408

This is the spec for the FATCA GIIN.

19 digits, alphanumeric and only uppercase, in 4 groups, each separated by a compulsory dot/period:

XXXXXX.XXXXX.XX.XXX

First two groups are alphanumeric uppercase, but never include uppercase O.

3rd group seems to only allow strict combination of 2 uppercase letters:

LE|SL|ME|BR|SP

4th group is only digits.

I have this so far, but am stuck on how to add that 'never allow O' rule:

[A-Z0-9]){6}\.[A-Z0-9]){5}\.(LE|SL|ME|BR|SP)\.\d{3}

So how can I restrict those first 2 groups to now allow the O?

NOTE - this is for Ruby

3 Answers

You may use character class intersection and - to match the entire string - anchors:

/\A[A-Z0-9&&[^O]]{6}\.[A-Z0-9&&[^O]]{5}\.(?:LE|SL|ME|BR|SP)\.\d{3}\z/

To match as whole word only use word boundaries, \b, instead of anchors:

/\b[A-Z0-9&&[^O]]{6}\.[A-Z0-9&&[^O]]{5}\.(?:LE|SL|ME|BR|SP)\.\d{3}\b/

See the Rubular demo.

Details

  • \A - start of string
  • [A-Z0-9&&[^O]]{6} - 6 uppercase letters or digits but not O
  • \. - dot
  • [A-Z0-9&&[^O]]{5} - 5 uppercase letters or digits but not O
  • \. - dot
  • (?:LE|SL|ME|BR|SP) - LE, SL, ME, BR or SP
  • \. - dot
  • \d{3} - any three digits
  • \z - end of string

The format of the current pattern is not correct, there are unclosed groups.

To omit the O you could use [A-NP-Z]

If you don't need the groups you could use:

\b[A-NP-Z0-9]{6}\.[A-NP-Z0-9]{5}\.(?:LE|SL|ME|BR|SP)\.\d{3}\b

Explanation

  • \b Word boundary
  • [A-NP-Z0-9]{6} Match 6 times A-Z without O
  • \. Match .
  • [A-NP-Z0-9]{5} Match 5 times A-Z0-9 without O
  • \. Match .
  • (?:LE|SL|ME|BR|SP) Match any of the lister
  • \. Match .
  • \d{3} Match 3 digits
  • \b Match word boundary

Regex demo

You could add word boundaries \b around the pattern to prevent the start and end being part of a larger word. Or you could add \A and \z anchors to match the start and the end of the string.

It turns out I needed something called a negative look-ahead:

(?:(?![O])

which basically says 'except O' (in the group that follows, hence 'look-ahead').

So the final solution is this (I think, not sure but seems to work):

(?:(?![O])[A-Z0-9]){6}\.(?:(?![O])[A-Z0-9]){5}\.(?:LE|SL|ME|BR|SP)\.\d{3}
Related