I have a range of card number prefixes of various lengths e.g. 11220-11221
, 6337461000000000-6337468549999999
, 945-965
.
How can I check to see if a card number (16 character string) e.g. 6337468549960326
starts with a defined prefix?
I thought I could try to add all the possible prefix values between the start and end values to some kind of list and then check if the card number begins with one of the possible prefixes however obviously the prefix list could be very large!
With the code I created using a similar logic, I get an out of memory exception when adding to my list _prefixes
.
private string _ranges = "11220, 11221; 6337461000000000, 6337468549999999; 945, 965;"
private HashSet<string>() _prefixes;
public bool IsCardNumberValid(string cardNumber)
{
this.PopulatePrefixes();
return this._prefixes.Any(x => cardNumber.StartsWith(x));
}
private void PopulatePrefixes()
{
if (string.IsNullOrWhiteSpace(this._ranges))
{
return;
}
string[] array2 = rangeString.Split(';');
for (int i = 0; i < array2.Length; i )
{
string[] array3 = array2[i].Split(',');
if (array3.Length == 2)
{
var minRange = Convert.ToInt64(array3[0]);
var maxRange = Convert.ToInt64(array3[1]);
lock (this.rangeLock)
{
this._prefixes = new HashSet<string>();
for (var x = minRange; x <= maxRange; x )
{
this._prefixes.Add(x.ToString());
}
}
}
}
}
CodePudding user response:
Since card number contains only digits, and is of fixed size (16 characters) you can pad your lower bound prefix with 0s to the right up to 16 characters, and pad upper bound prefix with 9s to the right up to 16 characters, and then do numeric comparision (we assume that both lower and higher bound prefixes are inclusive). For example, "945-965" prefix means your card number is >= than 9450000000000000 and <= than 9659999999999999. Sample code:
private string _rangesRaw = "11220, 11221; 6337461000000000, 6337468549999999; 945, 965;";
private List<Range> _prefixes = new List<Range>();
public bool IsCardNumberValid(string cardNumber) {
this.PopulatePrefixes();
var cardNumberAsLong = long.Parse(cardNumber);
return this._prefixes.Any(x => cardNumberAsLong >= x.Min && cardNumberAsLong <= x.Max);
}
private void PopulatePrefixes() {
foreach (var range in _rangesRaw.Split(";")) {
if (String.IsNullOrWhiteSpace(range))
continue;
var min = range.Split(",")[0].Trim();
if (min.Length < 16)
min = min new string('0', 16 - min.Length);
var max = range.Split(",")[1].Trim();
if (max.Length < 16)
max = max new string('9', 16 - max.Length);
_prefixes.Add(new Range(long.Parse(min), long.Parse(max)));
}
}
class Range {
public Range(long min, long max) {
// probably want to throw here if min > max
Min = min;
Max = max;
}
public long Min {get;}
public long Max{get;}
}
CodePudding user response:
i would check if the prefix of the card number falls into one of the ranges. here is a small example for doing so:
public class CardTrouble
{
private static string _ranges = "11220, 11221; 6337461000000000, 6337468549999999; 945, 965; 5, 1000;";
private static List<PrefixRange> _prefixRanges = new List<PrefixRange>();
public static void DoCardTrouble()
{
PopulatePrefixRanges();
IsCardNumberValid("11219");
}
public static bool IsCardNumberValid(string cardNumber)
{
foreach(var range in _prefixRanges)
{
var minLength = range.Min.ToString().Length;
var maxLength = range.Max.ToString().Length;
if (minLength <= cardNumber.Length && cardNumber.Length <= maxLength)
{
var pCardNumber = long.Parse(cardNumber.Substring(0, range.Max.ToString().Length));
if (range.Min <= pCardNumber && pCardNumber <= range.Max)
{
return false;
}
}
}
return true;
}
private static void PopulatePrefixRanges()
{
var sRanges = _ranges.Split(";");
foreach(var sRange in sRanges)
{
if (!string.IsNullOrWhiteSpace(sRange))
{
var prefixRange = new PrefixRange();
prefixRange.Min = long.Parse(sRange.Split(",")[0]);
prefixRange.Max = long.Parse(sRange.Split(",")[1]);
_prefixRanges.Add(prefixRange);
}
}
}
}
public class PrefixRange
{
public long Min { get; set; }
public long Max { get; set; }
}
CodePudding user response:
I think it doesn't need to convert prefix ranges to be numerical ranges. Here is sample code that could work with alphanumeric ranges.
private string string _ranges = "11220, 11221; 6337461000000000, 6337468549999999; 945, 965;";
private string List<string[]> _listRanges = null;
public bool IsCardNumberValid(string cardNumber)
{
if (this._listRanges == null)
this._listRanges = this.PopulatePrefixes(this._ranges);
return this._listRanges.Any(range => range[0].CompareTo(cardNumber) <= 0
&& range[1].CompareTo(cardNumber) >= 0);
}
private string List<string[]> PopulatePrefixes(string inputRanges)
{
var listRanges = new List<string[]>();
if (string.IsNullOrWhiteSpace(inputRanges))
{
return listRanges;
}
string[] ranges = inputRanges.Split(';');
foreach(var item in ranges) {
if (string.IsNullOrWhiteSpace(item)) continue;
var range = item.Split(',');
if (range.Length > 0) {
listRanges.Add(new string[2]);
var index = listRanges.Count - 1;
// add lower bound letter for start of the range
listRanges[index][0] = range[0].Trim() "0";
// add upper bound letter for end of the range
listRanges[index][1] = range.Length > 1 ? range[1].Trim() "z" : "z";
}
}
return listRanges;
}