-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCheckDigits.cs
238 lines (200 loc) · 6.91 KB
/
CheckDigits.cs
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
using System;
using System.Collections.Generic;
using System.Text;
namespace ISO7064
{
public class CheckDigits
{
public const string NumericCharSet = "0123456789";
public const string Mod112CharSet = "0123456789X";
public const string HexCharSet = "0123456789ABCDEF";
public const string AlphaCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public const string AlphanumericCharSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public const string Mod372CharSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*";
/// <summary>
/// Calculates a check digit based on ISO 7064.
/// </summary>
/// <param name="value">The string to check.</param>
/// <param name="charSet">A character set containing all possible characters used in the supplied value.</param>
/// <param name="doubleDigit">Specifies whether or not to use a double digit check digit.</param>
/// <returns>Returns the value with the check digit(s) appended.</returns>
public static string CalculateCheckDigit(string value, string charSet, bool doubleDigit)
{
int radix, modulus;
GetCheckDigitRadixAndModulus(charSet, doubleDigit, out radix, out modulus);
if (modulus != radix + 1)
return CalculatePureSystemCheckDigit(value, radix, modulus, charSet, doubleDigit);
else
return CalculateHybridSystemCheckDigit(value, charSet);
}
//Algorithm from: https://github.com/danieltwagner/iso7064.
public static string CalculatePureSystemCheckDigit(string value, int radix, int modulus, string charSet, bool doubleDigit)
{
if (String.IsNullOrEmpty(value))
return null;
value = value.ToUpper();
int p = 0;
foreach (char c in value)
{
int i = charSet.IndexOf(c);
if (i == -1)
return null;
p = ((p + i) * radix) % modulus;
}
if (doubleDigit)
p = (p * radix) % modulus;
int checkDigit = (modulus - p + 1) % modulus;
if (doubleDigit)
{
int second = checkDigit % radix;
int first = (checkDigit - second) / radix;
return value + charSet[first] + charSet[second];
}
else
return value + charSet[checkDigit];
}
//Algorithm from: http://www.codeproject.com/Articles/16540/Error-Detection-Based-on-Check-Digit-Schemes
public static string CalculateHybridSystemCheckDigit(string value, string charSet)
{
if (String.IsNullOrEmpty(value))
return null;
value = value.ToUpper();
int radix = charSet.Length;
int pos = radix;
foreach (char c in value)
{
int i = charSet.IndexOf(c);
if (i == -1)
return null;
pos += i;
if (pos > radix)
pos -= radix;
pos *= 2;
if (pos >= radix + 1)
pos -= radix + 1;
}
pos = radix + 1 - pos;
if (pos == radix)
pos = 0;
return value + charSet[pos];
}
/// <summary>
/// Returns the correct ISO 7064 radix and modulus for the given character set and digit count.
/// </summary>
private static void GetCheckDigitRadixAndModulus(string charSet, bool doubleDigit, out int radix, out int modulus)
{
radix = charSet.Length;
modulus = radix + 1;
if (doubleDigit)
{
//The modulus numbers below for double digit calculations are defined by ISO 7064.
switch (radix)
{
case 10:
modulus = 97;
break;
case 16: //Mod 251,16 isn't defined in ISO 7064, but it could be useful so I added it anyway.
modulus = 251;
break;
case 26:
modulus = 661;
break;
case 36:
modulus = 1271;
break;
}
}
else if (radix == 11)
{
//MOD 11,2 - Single digit 0-9 check with an added 'X' check digit.
modulus = 11;
radix = 2;
}
else if (radix == 37)
{
//MOD 37,2 - Single digit 0-9,A-Z check with an added '*' check digit.
modulus = 37;
radix = 2;
}
if (radix != 2 && radix != 10 && radix != 16 && radix != 26 && radix != 36)
throw new ArgumentException("Invalid character set.", "charSet");
}
/// <summary>
/// Verifies that the last character(s) of the supplied value are valid check digit(s).
/// </summary>
public static bool VerifyCheckDigit(string value, string charSet, bool doubleDigit)
{
int radix, modulus;
GetCheckDigitRadixAndModulus(charSet, doubleDigit, out radix, out modulus);
return VerifyCheckDigit(value, radix, modulus, charSet, doubleDigit);
}
public static bool VerifyCheckDigit(string value, int radix, int modulus, string charSet, bool doubleDigit)
{
int numDigits = (doubleDigit ? 2 : 1);
if (value == null || value.Length <= numDigits)
return false;
value = value.ToUpper();
string origValue = value.Substring(0, value.Length - numDigits);
if (modulus != radix + 1)
return (value == CalculatePureSystemCheckDigit(origValue, radix, modulus, charSet, doubleDigit));
else
return (value == CalculateHybridSystemCheckDigit(origValue, charSet));
}
/// <summary>
/// Calculates ISO 7064 MOD 11,10 in single digit mode and MOD 97,10 in double digit mode.
/// </summary>
public static string CalculateNumericCheckDigit(string value, bool doubleDigit)
{
return CalculateCheckDigit(value, NumericCharSet, doubleDigit);
}
/// <summary>
/// Verifies ISO 7064 MOD 11,10 in single digit mode and MOD 97,10 in double digit mode.
/// </summary>
public static bool VerifyNumericCheckDigit(string value, bool doubleDigit)
{
return VerifyCheckDigit(value, NumericCharSet, doubleDigit);
}
/// <summary>
/// Calculates ISO 7064 MOD 17,16 in single digit mode and MOD 251,16 in double digit mode.
/// </summary>
public static string CalculateHexCheckDigit(string value, bool doubleDigit)
{
return CalculateCheckDigit(value, HexCharSet, doubleDigit);
}
/// <summary>
/// Verifies ISO 7064 MOD 11,10 in single digit mode and MOD 97,10 in double digit mode.
/// </summary>
public static bool VerifyHexCheckDigit(string value, bool doubleDigit)
{
return VerifyCheckDigit(value, HexCharSet, doubleDigit);
}
/// <summary>
/// Calculates ISO 7064 MOD 27,26 in single digit mode and MOD 661,26 in double digit mode.
/// </summary>
public static string CalculateAlphaCheckDigit(string value, bool doubleDigit)
{
return CalculateCheckDigit(value, AlphaCharSet, doubleDigit);
}
/// <summary>
/// Verifies ISO 7064 MOD 27,26 in single digit mode and MOD 661,26 in double digit mode.
/// </summary>
public static bool VerifyAlphaCheckDigit(string value, bool doubleDigit)
{
return VerifyCheckDigit(value, AlphaCharSet, doubleDigit);
}
/// <summary>
/// Calculates ISO 7064 MOD 37,36 in single digit mode and MOD 1271,36 in double digit mode.
/// </summary>
public static string CalculateAlphanumericCheckDigit(string value, bool doubleDigit)
{
return CalculateCheckDigit(value, AlphanumericCharSet, doubleDigit);
}
/// <summary>
/// Verifies ISO 7064 MOD 37,36 in single digit mode and MOD 1271,36 in double digit mode.
/// </summary>
public static bool VerifyAlphanumericCheckDigit(string value, bool doubleDigit)
{
return VerifyCheckDigit(value, AlphanumericCharSet, doubleDigit);
}
}
}