[ACCEPTED]-Validate credit card number-validation
In Swift
enum CardType: String {
case Unknown, Amex, Visa, MasterCard, Diners, Discover, JCB, Elo, Hipercard, UnionPay
static let allCards = [Amex, Visa, MasterCard, Diners, Discover, JCB, Elo, Hipercard, UnionPay]
var regex : String {
switch self {
case .Amex:
return "^3[47][0-9]{5,}$"
case .Visa:
return "^4[0-9]{6,}([0-9]{3})?$"
case .MasterCard:
return "^(5[1-5][0-9]{4}|677189)[0-9]{5,}$"
case .Diners:
return "^3(?:0[0-5]|[68][0-9])[0-9]{4,}$"
case .Discover:
return "^6(?:011|5[0-9]{2})[0-9]{3,}$"
case .JCB:
return "^(?:2131|1800|35[0-9]{3})[0-9]{3,}$"
case .UnionPay:
return "^(62|88)[0-9]{5,}$"
case .Hipercard:
return "^(606282|3841)[0-9]{5,}$"
case .Elo:
return "^((((636368)|(438935)|(504175)|(451416)|(636297))[0-9]{0,10})|((5067)|(4576)|(4011))[0-9]{0,12})$"
default:
return ""
}
}
}
extension UITextField{
func validateCreditCardFormat()-> (type: CardType, valid: Bool) {
// Get only numbers from the input string
var input = self.text!
let numberOnly = input.stringByReplacingOccurrencesOfString("[^0-9]", withString: "", options: .RegularExpressionSearch)
var type: CardType = .Unknown
var formatted = ""
var valid = false
// detect card type
for card in CardType.allCards {
if (matchesRegex(card.regex, text: numberOnly)) {
type = card
break
}
}
// check validity
valid = luhnCheck(numberOnly)
// format
var formatted4 = ""
for character in numberOnly.characters {
if formatted4.characters.count == 4 {
formatted += formatted4 + " "
formatted4 = ""
}
formatted4.append(character)
}
formatted += formatted4 // the rest
// return the tuple
return (type, valid)
}
func matchesRegex(regex: String!, text: String!) -> Bool {
do {
let regex = try NSRegularExpression(pattern: regex, options: [.CaseInsensitive])
let nsString = text as NSString
let match = regex.firstMatchInString(text, options: [], range: NSMakeRange(0, nsString.length))
return (match != nil)
} catch {
return false
}
}
func luhnCheck(number: String) -> Bool {
var sum = 0
let digitStrings = number.characters.reverse().map { String($0) }
for tuple in digitStrings.enumerate() {
guard let digit = Int(tuple.element) else { return false }
let odd = tuple.index % 2 == 1
switch (odd, digit) {
case (true, 9):
sum += 9
case (true, 0...8):
sum += (digit * 2) % 9
default:
sum += digit
}
}
return sum % 10 == 0
}
}
form more go to http://kalapun.com/posts/card-checking-in-swift/
0
Don't change the user's entered text, it 19 will just cause confusion. Don't cause the 18 user to think: WTF. The user entered the 17 number in the way he understood, honor that 16 as much as possible.
Just sanitize what the 15 user has entered. Generally just remove 14 all leading, training and interspersed space 13 characters, possibly any non-numeric characters. Then 12 ensure the entered text is all numeric and 11 of the correct length.
Keep in mind that 10 the number can have a length of 13 to 19 9 digits, American Express is 15 digits. See: Bank card number
Consider 8 the code:
if ([temp.text length]>19) {
txtCard.text= [temp.text substringToIndex:[temp.text length] - 1];
}
If the user entered an extra space 7 character between groups the last digit 6 will be deleted. It is all to easy to come 5 up with such a scheme will avoid all possible 4 pitfalls.
Example: "1234 4567 9012 3 3456" would be truncated to "1234 2 4567 9012 345".
Extra, Method to verify the check digit:
+ (BOOL)isValidCheckDigitForCardNumberString:(NSString *)cardNumberString {
int checkSum = 0;
uint8_t *cardDigitArray = (uint8_t *)[cardNumberString dataUsingEncoding:NSUTF8StringEncoding].bytes;
int digitsCount = (int)cardNumberString.length;
BOOL odd = cardNumberString.length % 2;
for (int digitIndex=0; digitIndex<digitsCount; digitIndex++) {
uint8_t cardDigit = cardDigitArray[digitIndex] - '0';
if (digitIndex % 2 == odd) {
cardDigit = cardDigit * 2;
cardDigit = cardDigit / 10 + cardDigit % 10;
}
checkSum += cardDigit;
}
return (checkSum % 10 == 0);
}
BOOL checkDigitValid = [TestClass isValidCheckDigitForCardNumberString:@"371238839571772"];
NSLog(@"check digit valid: %@", checkDigitMatch ? @"yes" : @"no");
Output:
check 1 digit valid: yes
i am using this one in one of my app for 1 credit card like format
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init] ;
if([string length]==0)
{
[formatter setGroupingSeparator:@"-"];
[formatter setGroupingSize:4];
[formatter setUsesGroupingSeparator:YES];
[formatter setSecondaryGroupingSize:2];
NSString *num = textField.text ;
num= [num stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSString *str = [formatter stringFromNumber:[NSNumber numberWithDouble:[num doubleValue]]];
[formatter release];
textField.text=str;
NSLog(@"%@",str);
return YES;
}
else {
[formatter setGroupingSeparator:@"-"];
[formatter setGroupingSize:2];
[formatter setUsesGroupingSeparator:YES];
[formatter setSecondaryGroupingSize:2];
NSString *num = textField.text ;
if(![num isEqualToString:@""])
{
num= [num stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSString *str = [formatter stringFromNumber:[NSNumber numberWithDouble:[num doubleValue]]];
[formatter release];
textField.text=str;
}
//NSLog(@"%@",str);
return YES;
}
//[formatter setLenient:YES];
}
Here is my quick solution:
#define kLENGTH 4
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (string.length > 0) {
NSUInteger length = textField.text.length;
int cntr = (int)((length - (length/kLENGTH)) / kLENGTH);
if (!(((length + 1) % kLENGTH) - cntr)) {
NSString *str = [textField.text stringByAppendingString:[NSString stringWithFormat:@"%@ ", string]];
textField.text = str;
return NO;
}
} else {
if ([textField.text hasSuffix:@" "]) {
textField.text = [textField.text substringToIndex:textField.text.length - 2];
return NO;
}
}
return YES;
}
0
If you want to maintain your current approach, I'd 7 suggest stripping all the spaces out and 6 then reinserting them at the right places, something 5 like:
-(void)cardNumberValidation:(id)sender
{
NSString* text = [sender text];
// Strip out all spaces
text = [text stringByReplacingOccurrencesOfString:@" " withString:@""];
// Truncate to 16 characters
if(text.length)
text = [text substringToIndex:16];
// Insert spaces
if(text.length > 12)
text = [text stringByReplacingCharactersInRange:NSMakeRange(12, 0) withString:@" "];
if(text.length > 8)
text = [text stringByReplacingCharactersInRange:NSMakeRange(8, 0) withString:@" "];
if(text.length > 4)
text = [text stringByReplacingCharactersInRange:NSMakeRange(4, 0) withString:@" "];
[sender setText:text];
}
That said, the idea of changing the 4 users text on them can be confusing to the 3 user, and this approach is very dependent 2 on only accepting VISA and/or MasterCard 1 as other card issuers use different formats.
Solution in Swift:
let z = 4, intervalString = " "
func canInsert(atLocation y:Int) -> Bool { return ((1 + y)%(z + 1) == 0) ? true : false }
func canRemove(atLocation y:Int) -> Bool { return (y != 0) ? (y%(z + 1) == 0) : false }
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let nsText = textField.text! as NSString
if range.location == 19 { return false }
if range.length == 0 && canInsert(atLocation: range.location) {
textField.text! = textField.text! + intervalString + string
return false
}
if range.length == 1 && canRemove(atLocation: range.location) {
textField.text! = nsText.stringByReplacingCharactersInRange(NSMakeRange(range.location-1, 2), withString: "")
return false
}
return true
}
0
You can do this by using following:
class PaymentViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textFieldCardNumber: UITextField!
//for keeping track of cursor in text field for setting limit by Chetan
var cardNumberCursorPreviousPosition = 0
//MARK: - LifeCycle Methods
override func viewDidLoad() {
super.viewDidLoad()
self.textFieldCardNumber.delegate = self
//for applying did change event on text fields
self.textFieldCardNumber.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldDidChange(textField: UITextField) {
//logic for adding hyphen after each 4 digits
if textField == self.textFieldCardNumber {
if count(self.textFieldCardNumber.text) <= 7 {
var cardType: String = cardValidator.checkCardType(self.textFieldCardNumber.text)
println("Card Type : \(cardType)")
}
//for applying hyphen
if (count(textFieldCardNumber.text) == 4 && cardNumberCursorPreviousPosition == 3) || (count(textFieldCardNumber.text) == 9 && cardNumberCursorPreviousPosition == 8) ||
(count(textFieldCardNumber.text) == 14 && cardNumberCursorPreviousPosition == 13) {
textFieldCardNumber.text = "\(textFieldCardNumber.text)-"
}
//for removing hyphen and its preceding character/number
if (count(textFieldCardNumber.text) == 4 && cardNumberCursorPreviousPosition == 5) ||
(count(textFieldCardNumber.text) == 9 && cardNumberCursorPreviousPosition == 10) ||
(count(textFieldCardNumber.text) == 14 && cardNumberCursorPreviousPosition == 15) {
textFieldCardNumber.text = textFieldCardNumber.text.substringToIndex(advance(textFieldCardNumber.text.endIndex, -1))
}
cardNumberCursorPreviousPosition = count(textFieldCardNumber.text)
}
}
In the 2 above code I have given hyphen. You can 1 replace it with space.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.