日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET Core 如何生成信用卡卡号

發(fā)布時間:2023/12/4 asp.net 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core 如何生成信用卡卡号 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

點擊上方藍字關注“汪宇杰博客”

導語

上個月我寫了《.NET Core 如何驗證信用卡卡號》,不少朋友表示挺有興趣。在金融科技行業(yè)的實際工作中,通常還需要生成信用卡卡號用來測試,今天我就來教大家如何生成信用卡卡號。

上回的改進

上篇文章寫完后,我對代碼進行了一些改進,除了使用方法上的差別,還改進了一處潛在的性能問題。

原本將卡號字符串轉換為int數(shù)組的函數(shù)為:

public static int[] GetDigitsArrayFromCardNumber(string cardNumber)

{

? ? var digits =?cardNumber.Select(p => int.Parse(p.ToString())).ToArray();

? ? return digits;

}

它所存在的問題是,為了將 char 類型轉換為 int,做了一次 ToString() 操作,盡管 .NET CLR 會在內存里保留相同內容的 string,但不必要的 string 分配仍會有一定的開銷。對于信用卡卡號,此處的 char 一定是代表數(shù)字的字符,不可能是其他英文字符或符號,因此可以通過 ASCII 運算來進行高效轉換。

我們只需要用 char 減去 '0',即可得到對應的 int 類型,例如 '8' - '0' = 8:

還記得大學計算機基礎課里學的 ASCII 碼?嗎?字符 8 的 ASCII 碼為 56,字符 0 的 ASCII 碼為 48,因為 56 - 48 = 8,因此字符 8 - 字符 0 = 8。

至于性能的對比,爭論再多理論也不如實際測一下有說服力。我們用兩種方法,均執(zhí)行?996007?次(嗯?這個數(shù)字有點眼熟),對比總時間。

轉換string類型,耗時20ms

使用char計算,耗時 1ms

所以,不要小看這些“騷操作”,平時代碼里看到同事這么寫不要覺得只是在裝逼。盡管有時候代碼閱讀體驗沒有那么直觀,但如果你的業(yè)務面臨苛刻的壓力時,能夠明顯體驗到性能區(qū)別。.NET Core 的基礎類庫源代碼里也有不少類似這樣的基礎類型騷操作,有興趣的讀者可以去翻翻。

然而裝逼,是人類社會的剛需,光用char計算逼格還不夠,還記得上回的 Luhn 算法嗎?原來的代碼如下,我只是把維基百科上公開定義的算法直接翻譯成C#:

public static bool IsLuhnValid(int[] digits)

{

? ? var sum = 0;

? ? var alt = false;

? ? for (var i = digits.Length - 1; i >= 0; i--)

? ? {

? ? ? ? if (alt)

? ? ? ? {

? ? ? ? ? ? digits[i] *= 2;

? ? ? ? ? ? if (digits[i] > 9)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? digits[i] -= 9;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? sum += digits[i];

? ? ? ? alt = !alt;

? ? }

? ? return sum % 10 == 0;

}

而C#就應該用出C#的味道不是?代碼逼格化以后:

public static bool IsLuhnValid(int[] digits)

{

? ? var sum = digits.Reverse()

? ? ? ? .Select((digit, i) =>

? ? ? ? ? ? ? ? (i + 1) % 2 == 0

? ? ? ? ? ? ? ? ? digit * 2 > 9 ? digit * 2 - 9 : digit * 2

? ? ? ? ? ? ? ? : digit)

? ? ? ? .Sum();

? ? return sum % 10 == 0;

}

深藏功與名。

生成卡號

上回理解了 Luhn 算法之后,我們不難發(fā)現(xiàn),驗證卡號的精髓無非在于最后的校驗位(Check Digit)。也就是說,生成卡號其實只要生成有效的校驗位,其他數(shù)字隨機,只要校驗位正確,就可以通過 Luhn 檢查。

校驗位生成

還記得校驗位怎么來的嗎?就拿上回的例子卡號?6011000990139424,去掉校驗位4以后,計算的SUM值為4646x9 = 414,尾數(shù)為4,即校驗位。因此對于我們自己隨機生成的卡號,也只要計算除了校驗位以外的SUM,然后乘以9,再取尾數(shù)即可

因為計算SUM的方法很相似,只是用來翻倍-9的奇偶位不同,所以我重構一下代碼,將計算邏輯封裝:

public static bool IsLuhnValid(int[] digits)

{

? ? var sum = CalculateSum(digits, 1);

? ? return sum % 10 == 0;

}

private static int CalculateSum(int[] digits, int bitShift = 0)

{

? ? var sum = digits.Reverse()

? ? ? ? ? ? ? ? ? ? ? ? .Select((digit, i) =>

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (i + bitShift) % 2 == 0

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? digit * 2 > 9 ? digit * 2 - 9 : digit * 2

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? : digit)

? ? ? ? ? ? ? ??? ? ? ? .Sum();

? ? return sum;

}

生成校驗位就能這么操作:

public static int GenerateCheckDigit(int[] digits)

{

? ? var sum = CalculateSum(digits);

? ? var lastDigit = sum * 9 % 10;

? ? return lastDigit;

}

該函數(shù)的?digits 參數(shù)接受的值是不包含校驗位的信用卡其余卡號,例如還是之前的例子?6011000990139424,去掉校驗位4,傳給?GenerateCheckDigit() 的為?601100099013942。因為少了一位,所以bitShift參數(shù)就用默認值0,以確保奇偶位不會錯位。

% 10 用來高性能取尾數(shù)。嗯?差點又 ToString() 了是嗎?

測試計算結果準確,如下:

隨機數(shù)騷操作

可能大家覺得C#生成隨機數(shù)有什么難的,不就是一個 Random 類型嗎?但實際情況是,如果Random在static修飾符的情況下,這可不一定線程安全,具體原因不在本文討論范圍內,直接給出解決方案。(嗯,差點加鎖了是嗎?性能可沒這個好)

private static int _seed = Environment.TickCount;

private static readonly ThreadLocal<Random> Random =

? ? new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref _seed)));

參考:https://stackoverflow.com/questions/19270507/correct-way-to-use-random-in-multithread-application

Put Together

實際生成信用卡卡號,一般會給定BIN,因此我的函數(shù)設計為接受BIN前綴、卡號位數(shù),生成符合 Luhn 的隨機卡號。

public static string GenerateCardNumber(string bin, int length)

{

? ? int[] digits = new int[length];

? ? var prefixDigits = bin.Select(p => p - '0').ToArray();

? ? for (var i = 0; i < prefixDigits.Length; i++)

? ? {

? ? ? ? digits[i] = prefixDigits[i];

? ? }

? ? for (var i = bin.Length; i < length - 1; i++)

? ? {

? ? ? ? var digit = Random.Value.Next(0, 10);

? ? ? ? digits[i] = digit;

? ? }

? ? digits[length - 1] = Luhn.GenerateCheckDigit(digits[..(length -1)]);

? ? return string.Join(null, digits);

}

還是考慮到性能,我沒有用 StringBuilder 拼接卡號,更沒有用 string += 拼接。設計類庫給別人你用的話,一定要注意場景,在我的實際工作中,生成卡號往往是大批量操作,有性能要求,所以寫代碼要盡量拷問每一處細節(jié)。

使用方法:

var bin = "485246";

int length = 16;

var cn = CreditCardGenerator.GenerateCardNumber(bin, length);

Assert.IsNotEmpty(cn);

Assert.IsTrue(cn.Length == length);

var result = CreditCardValidator.ValidCardNumber(cn);

Assert.IsTrue(result.CardNumberFormat == CardNumberFormat.Valid_LuhnOnly

? ? ? ? ? ? ? || result.CardNumberFormat == CardNumberFormat.Valid_BINTest);

批量生成:

var bin = "485246";

int length = 16;

var cardNumbers = new List<string>();

for (int i = 0; i < 128; i++)

{

? ? var cn = CreditCardGenerator.GenerateCardNumber(bin, length);

? ? cardNumbers.Add(cn);

}

var isUnique = cardNumbers.GroupBy(x => x).All(g => g.Count() == 1);

Assert.IsTrue(isUnique);

項目依然在我的交友平臺上:https://github.com/EdiWang/Edi.CreditCardUtils

大家如果有什么建議,或是再能進一步改進優(yōu)化,歡迎提交流及PR。

總結

以上是生活随笔為你收集整理的.NET Core 如何生成信用卡卡号的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。