You cannot rely on a regex to validate card numbers. You need a recent card validation table that includes lengths for ranges and range to type mappings. Your payment gateway provider should be able to provide you with an up to date validation table.
You can often rely on Luhn for an is-this-number-made-up type of validation but in order to pass your gateway's liability tests, you need to validate that the user has entered the write card type for the number and if a start date is required by the provider, it must be entered, etc...
Here's a Luhn example in C#:
public static bool IsLuhnValid(string cardNumber) {
if (string.IsNullOrEmpty(cardNumber))
return false;
Int64 cardNumberAsBigInt;
if (!Int64.TryParse(cardNumber, out cardNumberAsBigInt) || (cardNumberAsBigInt == 0))
return false;
int indicator = 1;
int firstNumberToAdd = 0;
int secondNumberToAdd = 0;
for (int i = cardNumber.Length - 1; i >= 0; i--) {
int currentNumber = int.Parse(cardNumber[i].ToString());
if (indicator == 1) {
firstNumberToAdd += currentNumber;
indicator = 0;
}
else {
int doubleCurrentNumber = currentNumber + currentNumber;
if (doubleCurrentNumber >= 10) {
int num1 = Convert.ToInt32(doubleCurrentNumber.ToString().Substring(0, 1));
int num2 = Convert.ToInt32(doubleCurrentNumber.ToString().Substring(1, 1));
secondNumberToAdd += num1 + num2;
}
else {
secondNumberToAdd += doubleCurrentNumber;
}
indicator = 1;
}
}
return ((firstNumberToAdd + secondNumberToAdd) % 10 == 0);
}