public sealed class Isin { private string m_cc, m_nsin; private int m_digest; public static bool LooksLike(string isin) { if (string.IsNullOrEmpty(isin)) return false; isin = isin.Trim(); if (string.IsNullOrEmpty(isin)) return false; Isin obj; return Isin.TryParse(isin, out obj); } public static bool TryParse(string isin, out Isin obj) { bool retval = false; Isin i = new Isin(); if (retval = i.ParseInternal(isin)) obj = i; else obj = null; return retval; } public static Isin Parse(string isin) { return new Isin(isin); } public Isin(string isin) { if (!this.ParseInternal(isin)) throw new FormatException("Not a isin."); } private Isin() { } private bool ParseInternal(string isin) { bool retval = false; do { isin = isin.Trim().ToUpperInvariant(); if (isin.Length != 12) break; retval = isin.StartsWith("IX") && isin.EndsWith("X"); // special case if (retval || (retval = (Isin.DoubleAddDouble(isin) == 0))) { m_cc = isin.Substring(0, 2); m_nsin = isin.Substring(1, 10); if (!int.TryParse(isin.Substring(11), out m_digest)) m_digest = int.MaxValue; } } while(false); return retval; } private static int DoubleAddDouble(string src) { int s = 0; int a = src.Length == 12 ? 1 : 2; for (int i = src.Length - 1; i >= 0; i--) { int c = src[i]; if (c > '9') // letter { c -= ('A' - 10); s += (3 - a) * (c / 10) + a * c + (a - 1) * (c % 10) / 5; } else // number { c -= '0'; s += a * c + (a - 1) * (c / 5); a = 3 - a; } } s %= 10; return (10 - s % 10) % 10; } public string CountryCode { get { return m_cc; } } public string Nsin { get { return m_nsin; } } public int Digest { get { return m_digest; } } public override string ToString() { if (this.Digest == int.MaxValue) return string.Format("{0}{1}X", this.CountryCode, this.Nsin); else return string.Format("{0}{1}{2}", this.CountryCode, this.Nsin, this.Digest); } }