我从用户那里取信用卡号作为输入。我想允许16个数字,并希望在每个4个数字后格式化空格。为此,我做了以下。
-(void)cardNumberValidation:(id)sender{
UITextField *temp=sender;
if ([temp.text length]>19) {
txtCard.text= [temp.text substringToIndex:[temp.text length] - 1];
}
if ([temp.text length]==4) {
txtCard.text=[NSString stringWithFormat:@"%@ ",temp.text];
}
if ([temp.text length]==9) {
txtCard.text=[NSString stringWithFormat:@"%@ ",temp.text];
}
if ([temp.text length]==14) {
NSString *lastChar = [txtCard.text substringFromIndex:[txtCard.text length] - 1];
txtCard.text=[NSString stringWithFormat:@"%@ ",temp.text];
}
}
但是现在当用户输入所有字符后将删除字符然后如果它将达到15个字符,然后用户将删除另外一个字符,那么此代码将在其后添加空格并且不允许进一步删除它。
任何人都可以就此或更好的方式向我提出建议。
答案 0 :(得分:7)
在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
}
}
答案 1 :(得分:4)
不要更改用户输入的文字,这只会引起混淆。不要让用户思考:WTF。用户以他理解的方式输入了号码,尽可能地尊重他。
只需清理用户输入的内容即可。通常只删除所有前导,训练和散布的空格字符,可能是任何非数字字符。然后确保输入的文本全部为数字且长度正确。
请注意,该号码的长度为13至19位,American Express为15位。请参阅:Bank card number
考虑代码:
if ([temp.text length]>19) {
txtCard.text= [temp.text substringToIndex:[temp.text length] - 1];
}
如果用户在组之间输入了额外的空格字符,则最后一位数字将被删除。很容易想出这样的方案将避免所有可能的陷阱 示例:" 1234 4567 9012 3456"将被截断为" 1234 4567 9012 345"。
额外,Method to verify校验位:
+ (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");
输出:
检查数字有效:是
答案 2 :(得分:2)
我在我的应用程序中使用这个格式的信用卡
- (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];
}
答案 3 :(得分:1)
这是我的快速解决方案:
#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;
}
答案 4 :(得分:1)
如果你想保持目前的做法,我建议剥去所有空格,然后将它们重新插入正确的地方,例如:
-(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];
}
也就是说,更改用户文本的想法可能会让用户感到困惑,这种方法非常依赖于只接受VISA和/或万事达卡,因为其他发卡机构使用不同的格式。
答案 5 :(得分:1)
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
}
答案 6 :(得分:0)
答案 7 :(得分:0)
您可以使用以下方法执行此操作:
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)
}
}
在上面的代码中,我给出了连字符。你可以用空格替换它。