Skip to content

Commit 5a2e307

Browse files
authored
Merge pull request #48 from shinji-san/release-v1.1.0
Release v1.1.0 Added: - Add `ConvertAlphaNumericToNumeric` method to convert a string containing alphanumeric characters to a string containing only numeric characters (use case: converting an ISIN to a numeric string for Luhn validation). Resolves: #48
2 parents 42c2946 + bf46864 commit 5a2e307

File tree

6 files changed

+292
-17
lines changed

6 files changed

+292
-17
lines changed

CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [1.0.1] - 2024-02-19
7+
## [1.1.0] - 2024-03-30
8+
### Added
9+
- Add `ConvertAlphaNumericToNumeric` method to convert a string containing alphanumeric characters to a string containing only numeric characters (use case: converting an ISIN to a numeric string for Luhn validation).
10+
11+
## [1.0.1] - 2024-03-19
812
### Fixed
913
- Fixed a bug in `Luhn.ComputeLuhnNumber` and `Luhn.ComputeLuhnCheckDigit` methods that sometimes returned an incorrect result.
1014

@@ -42,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4246
### Added
4347
- Added initial version of LuhnDotNet
4448

49+
[1.1.0]: https://github.com/shinji-san/LuhnDotNet/compare/v1.0.1..v1.1.0
4550
[1.0.1]: https://github.com/shinji-san/LuhnDotNet/compare/v1.0.0..v1.0.1
4651
[1.0.0]: https://github.com/shinji-san/LuhnDotNet/compare/v0.2.0..v1.0.0
4752
[0.2.0]: https://github.com/shinji-san/LuhnDotNet/compare/v0.1.0..v0.2.0

README.md

+114-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# LuhnDotNet
22
An C# implementation of the Luhn algorithm.
33

4+
The Luhn algorithm is a checksum formula used to validate identification numbers like credit card numbers. It works by doubling every second digit from the right, summing all the digits, and checking if the total is a multiple of 10. It's widely used and is specified in ISO/IEC 7812-1.
5+
46
# Build & Test Status Of Default Branch
57
<table>
68
<thead>
@@ -61,9 +63,9 @@ An C# implementation of the Luhn algorithm.
6163
</thead>
6264
<tbody>
6365
<tr>
64-
<td rowspan=10><a href="https://github.com/shinji-san/LuhnDotNet/actions?query=workflow%3A%22LuhnDotNet+NuGet%22" target="_blank"><img src="https://github.com/shinji-san/LuhnDotNet/workflows/LuhnDotNet%20NuGet/badge.svg?branch=v1.0.1" alt="LuhnDotNet NuGet"/></a></td>
65-
<td rowspan=10><a href="https://badge.fury.io/nu/LuhnDotNet" target="_blank"><img src="https://badge.fury.io/nu/LuhnDotNet.svg" alt="NuGet Version 1.0.1"/></a></td>
66-
<td rowspan=10><a href="https://github.com/shinji-san/LuhnDotNet/tree/v1.0.1" target="_blank"><img src="https://img.shields.io/badge/LuhnDotNet-1.0.1-green.svg?logo=github&logoColor=959da5&color=2ebb4e&labelColor=2b3137" alt="Tag"/></a></td>
66+
<td rowspan=10><a href="https://github.com/shinji-san/LuhnDotNet/actions?query=workflow%3A%22LuhnDotNet+NuGet%22" target="_blank"><img src="https://github.com/shinji-san/LuhnDotNet/workflows/LuhnDotNet%20NuGet/badge.svg?branch=v1.1.0" alt="LuhnDotNet NuGet"/></a></td>
67+
<td rowspan=10><a href="https://badge.fury.io/nu/LuhnDotNet" target="_blank"><img src="https://badge.fury.io/nu/LuhnDotNet.svg" alt="NuGet Version 1.1.0"/></a></td>
68+
<td rowspan=10><a href="https://github.com/shinji-san/LuhnDotNet/tree/v1.1.0" target="_blank"><img src="https://img.shields.io/badge/LuhnDotNet-1.1.0-green.svg?logo=github&logoColor=959da5&color=2ebb4e&labelColor=2b3137" alt="Tag"/></a></td>
6769
<td>.NET 6</td>
6870
</tr>
6971
<tr>
@@ -100,10 +102,10 @@ An C# implementation of the Luhn algorithm.
100102

101103
1. Open a console and switch to the directory, containing your project file.
102104

103-
2. Use the following command to install version 1.0.1 of the LuhnDotNet package:
105+
2. Use the following command to install version 1.1.0 of the LuhnDotNet package:
104106

105107
```dotnetcli
106-
dotnet add package LuhnDotNet -v 1.0.1 -f <FRAMEWORK>
108+
dotnet add package LuhnDotNet -v 1.1.0 -f <FRAMEWORK>
107109
```
108110
109111
3. After the completion of the command, look at the project file to make sure that the package is successfully installed.
@@ -112,7 +114,7 @@ An C# implementation of the Luhn algorithm.
112114
113115
```xml
114116
<ItemGroup>
115-
<PackageReference Include="LuhnDotNet" Version="1.0.1" />
117+
<PackageReference Include="LuhnDotNet" Version="1.1.0" />
116118
</ItemGroup>
117119
```
118120
## Remove LuhnDotNet package
@@ -210,6 +212,101 @@ namespace Example4
210212
}
211213
```
212214

215+
## Validate ISIN with LuhnDotNet and ConvertAlphaNumericToNumeric
216+
217+
The `LuhnDotNet` library can be used in combination with the `ConvertAlphaNumericToNumeric` method to validate an International Securities Identification Number (ISIN). An ISIN uniquely identifies a security, such as stocks, bonds or derivatives. It is a 12-character alphanumeric code.
218+
219+
The `ConvertAlphaNumericToNumeric` method is used to convert the alphanumeric ISIN to a numeric string, where each letter in the input string is replaced by its decimal ASCII value minus 55. This numeric string can then be validated using the `Luhn.IsValid` method.
220+
221+
Here is an example of how to use these methods to validate an ISIN:
222+
223+
```csharp
224+
using System;
225+
using LuhnDotNet;
226+
227+
namespace Example5
228+
{
229+
public class Program
230+
{
231+
public static void Main(string[] args)
232+
{
233+
string isin = "US0378331005";
234+
bool isValid = Luhn.IsValid(isin.ConvertAlphaNumericToNumeric());
235+
236+
Console.WriteLine($"The ISIN {isin} is valid: {isValid}");
237+
}
238+
}
239+
}
240+
```
241+
## Compute ISIN Check Digit with LuhnDotNet and ConvertAlphaNumericToNumeric
242+
243+
The `LuhnDotNet` library provides the `ComputeLuhnCheckDigit` method which can be used to compute the check digit of a numeric string according to the Luhn algorithm. When dealing with an International Securities Identification Number (ISIN), which is a 12-character alphanumeric code, we first need to convert the alphanumeric ISIN to a numeric string. This can be achieved using the `ConvertAlphaNumericToNumeric` method.
244+
245+
Here is an example of how to compute the check digit of an ISIN:
246+
247+
```csharp
248+
using System;
249+
using LuhnDotNet;
250+
251+
namespace Example6
252+
{
253+
public class Program
254+
{
255+
public static void Main(string[] args)
256+
{
257+
string isinWithoutCheckDigit = "US037833100";
258+
byte checkDigit = Luhn.ComputeLuhnCheckDigit(isinWithoutCheckDigit.ConvertAlphaNumericToNumeric());
259+
260+
Console.WriteLine($"The check digit for ISIN {isinWithoutCheckDigit} is: {checkDigit}");
261+
}
262+
}
263+
}
264+
```
265+
266+
## Compute credit card number with LuhnDotNet
267+
The `LuhnDotNet` library can be used to compute the check digit of a credit card number. The check digit is the last digit of the credit card number, which is used to validate the number according to the Luhn algorithm.
268+
269+
```csharp
270+
using System;
271+
using LuhnDotNet;
272+
273+
namespace Example7
274+
{
275+
public class Program
276+
{
277+
public static void Main(string[] args)
278+
{
279+
string creditCardNumberWithoutCheckDigit = "4417 1234 5678 911".Replace(" ", "");
280+
byte checkDigit = Luhn.ComputeLuhnCheckDigit(creditCardNumberWithoutCheckDigit);
281+
282+
Console.WriteLine($"The check digit for credit card number {creditCardNumberWithoutCheckDigit} is: {checkDigit}");
283+
}
284+
}
285+
}
286+
```
287+
288+
## Validate credit card number with LuhnDotNet
289+
The `LuhnDotNet` library can be used to validate a credit card number according to the Luhn algorithm. The `IsValid` method returns `true` if the credit card number is valid, and `false` otherwise.
290+
291+
```csharp
292+
using System;
293+
using LuhnDotNet;
294+
295+
namespace Example8
296+
{
297+
public class Program
298+
{
299+
public static void Main(string[] args)
300+
{
301+
string creditCardNumber = "4417 1234 5678 9113".Replace(" ", "");
302+
bool isValid = Luhn.IsValid(creditCardNumber);
303+
304+
Console.WriteLine($"The credit card number {creditCardNumber} is valid: {isValid}");
305+
}
306+
}
307+
}
308+
```
309+
213310
# CLI building instructions
214311
For the following instructions, please make sure that you are connected to the internet. If necessary, NuGet will try to restore the [xUnit](https://xunit.net/) packages.
215312
## Using dotnet to build for .NET 6, .NET 7, .NET 8 and .NET FX 4.x
@@ -219,30 +316,36 @@ Use one of the following solutions with `dotnet` to build [LuhnDotNet](#luhndotn
219316

220317
The syntax is:
221318
```dotnetcli
222-
dotnet {build|test} -c {Debug|Release} LuhnDotNet.sln
319+
dotnet {restore|build|test} -c {Debug|Release} LuhnDotNet.sln
320+
```
321+
322+
### Restore NuGet packages
323+
324+
```dotnetcli
325+
dotnet restore LuhnDotNet.sln
223326
```
224327

225328
The instructions below are examples, which operate on the `LuhnDotNet.sln`.
226329
### Build Debug configuration
227330

228331
```dotnetcli
229-
dotnet build -c Debug LuhnDotNet.sln
332+
dotnet build -c Debug --no-restore LuhnDotNet.sln
230333
```
231334

232335
### Build Release configuration
233336

234337
```dotnetcli
235-
dotnet build -c Release LuhnDotNet.sln
338+
dotnet build -c Release --no-restore LuhnDotNet.sln
236339
```
237340

238341
### Test Debug configuration
239342

240343
```dotnetcli
241-
dotnet test -c Debug LuhnDotNet.sln
344+
dotnet test -c Debug --no-restore --no-build LuhnDotNet.sln
242345
```
243346

244347
### Test Release configuration
245348

246349
```dotnetcli
247-
dotnet test -c Release LuhnDotNet.sln
350+
dotnet test -c Release --no-restore --no-build LuhnDotNet.sln
248351
```

src/Luhn.cs

+63
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace LuhnDotNet
3838
using System.Diagnostics.CodeAnalysis;
3939
using System.Globalization;
4040
#if !NET6_0_OR_GREATER
41+
using System.Text;
4142
using System.Text.RegularExpressions;
4243
#endif
4344

@@ -162,6 +163,68 @@ public static bool IsValid(string number, byte checkDigit)
162163
.SumDigits() == 0;
163164
}
164165

166+
/// <summary>
167+
/// Converts an alphanumeric string to a numeric string.
168+
/// </summary>
169+
/// <param name="alphaNumeric">The alphanumeric string to convert.</param>
170+
/// <returns>A numeric string where each letter in the input string is replaced by its decimal ASCII value
171+
/// minus 55.</returns>
172+
/// <remarks>
173+
/// This method iterates over each character in the input string. If the character is a letter, it is replaced
174+
/// by its decimal ASCII value minus 55. If the character is a digit, it is left unchanged.
175+
/// </remarks>
176+
public static string ConvertAlphaNumericToNumeric(this string alphaNumeric)
177+
#if NET6_0_OR_GREATER
178+
{
179+
Span<char> result = stackalloc char[alphaNumeric.Length * 2];
180+
int index = 0;
181+
182+
foreach (char c in alphaNumeric.ToUpper())
183+
{
184+
if (char.IsLetter(c))
185+
{
186+
string numericValue = (c - 55).ToString();
187+
foreach (char numChar in numericValue)
188+
{
189+
result[index++] = numChar;
190+
}
191+
}
192+
else if (char.IsDigit(c))
193+
{
194+
result[index++] = c;
195+
}
196+
else
197+
{
198+
throw new ArgumentException($"The character '{c}' is not a letter or a digit!", nameof(alphaNumeric));
199+
}
200+
}
201+
202+
return result[..index].ToString();
203+
}
204+
#else
205+
{
206+
var result = new StringBuilder();
207+
208+
foreach (char c in alphaNumeric.ToUpper())
209+
{
210+
if (char.IsLetter(c))
211+
{
212+
result.Append(c - 55);
213+
}
214+
else if (char.IsDigit(c))
215+
{
216+
result.Append(c);
217+
}
218+
else
219+
{
220+
throw new ArgumentException($"The character '{c}' is not a letter or a digit!", nameof(alphaNumeric));
221+
}
222+
}
223+
224+
return result.ToString();
225+
}
226+
#endif
227+
165228
/// <summary>
166229
/// Doubling of every second digit.
167230
/// </summary>

src/LuhnDotNet.csproj

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@
66
<SignAssembly>True</SignAssembly>
77
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
88
<ImplicitUsings>disable</ImplicitUsings>
9+
<LangVersion>latest</LangVersion>
910
<Nullable>disable</Nullable>
1011
<Authors>Sebastian Walther</Authors>
1112
<PackageId>LuhnDotNet</PackageId>
1213
<PackageLicenseExpression>MIT</PackageLicenseExpression>
13-
<PackageReleaseNotes>Changelog: https://github.com/shinji-san/LuhnDotNet/blob/v1.0.1/CHANGELOG.md</PackageReleaseNotes>
14+
<PackageReleaseNotes>Changelog: https://github.com/shinji-san/LuhnDotNet/blob/v1.1.0/CHANGELOG.md</PackageReleaseNotes>
1415
<PackageDescription>An C# implementation of the Luhn algorithm</PackageDescription>
1516
<PackageReadmeFile>README.md</PackageReadmeFile>
1617
<PackageTags>luhn;luhn-algorithm</PackageTags>
1718
<PackageProjectUrl>https://github.com/shinji-san/LuhnDotNet</PackageProjectUrl>
1819
<RepositoryUrl>https://github.com/shinji-san/LuhnDotNet</RepositoryUrl>
1920
<RepositoryType>git</RepositoryType>
20-
<Version>1.0.1</Version>
21+
<Version>1.1.0</Version>
2122
<Authors>Sebastian Walther</Authors>
2223
<Company>Private Person</Company>
2324
<GenerateDocumentationFile>true</GenerateDocumentationFile>

src/Properties/AssemblyInfo.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
[assembly: Guid("bba40d96-b58d-4a8f-b6fc-3699e0addf98")]
1717

18-
[assembly: AssemblyVersion("1.0.1")]
19-
[assembly: AssemblyFileVersion("1.0.1")]
18+
[assembly: AssemblyVersion("1.1.0")]
19+
[assembly: AssemblyFileVersion("1.1.0")]
2020
[assembly: NeutralResourcesLanguage("en")]
2121

2222
[assembly: System.CLSCompliant(true)]

0 commit comments

Comments
 (0)