Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 什么';在UITextField中验证货币输入的最佳方法是什么?_Iphone_Cocoa Touch - Fatal编程技术网

Iphone 什么';在UITextField中验证货币输入的最佳方法是什么?

Iphone 什么';在UITextField中验证货币输入的最佳方法是什么?,iphone,cocoa-touch,Iphone,Cocoa Touch,我的应用程序允许用户在UITextField控件中输入数值(货币),但不幸的是,我希望可用的键盘布局不是内置选项之一,因此我必须在Interface Builder中选择“数字和标点符号”选项。以下是IB中相应的对话框窗口: 因此,当我的应用程序要求用户输入时,它会显示以下内容: 这很好,但是看看用户可以使用的所有额外密钥!人们可以很容易地在文本字段中输入“12;56!”,我想我必须以某种方式验证这一点 所以我的问题是:如何验证输入到UITextField中的货币值?也许您可以在控件上附加一

我的应用程序允许用户在
UITextField
控件中输入数值(货币),但不幸的是,我希望可用的键盘布局不是内置选项之一,因此我必须在Interface Builder中选择“数字和标点符号”选项。以下是IB中相应的对话框窗口:

因此,当我的应用程序要求用户输入时,它会显示以下内容:

这很好,但是看看用户可以使用的所有额外密钥!人们可以很容易地在文本字段中输入“12;56!”,我想我必须以某种方式验证这一点


所以我的问题是:如何验证输入到
UITextField
中的货币值?

也许您可以在控件上附加一个
UITextFieldDelegate
并让它实现
文本字段:shouldChangeCharactersRange:replacementString:
,如果它在字段中看到任何您不需要的字符,它可以拒绝它们。

文本字段:shouldChangeCharactersRange:replacementString:
由Marc提出的建议结合使用
NSNumberFormatterCurrencyStyle
通过
NSNumberFormatter
。这将处理货币格式的问题,并处理特定于语言环境的选项


如果您搜索,iPhone文档中会有一个“Cocoa数据格式编程指南”部分。遗憾的是,这里的大多数UI信息都是特定于Mac OS X的(在iPhone上不起作用),但它将向您展示如何使用格式化程序类。

使用NSNumberFormatter是正确的答案。它将处理验证,并将字符串转换为正确的对象类型。

虽然您可以在NSNumberFormatter中使用z,但我发现只需筛选出0-9和0之外的任何内容就更容易了

这对我来说很有效:

}
< /代码>

如果你想让它们只能输入数字,你也可以考虑数字键盘

使用SubDeCuffEngReloSnices按钮来弹出弹出键板,因为退格按钮不起作用。< /P> 数字格式化程序是一个不错的选择。这是我用来寻找正小数的一个例子。我在验证检查期间调用它-例如,当用户单击“保存”按钮时

- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    static NSString *numbers = @"0123456789";
    static NSString *numbersPeriod = @"01234567890.";
    static NSString *numbersComma = @"0123456789,";

    //NSLog(@"%d %d %@", range.location, range.length, string);
    if (range.length > 0 && [string length] == 0) {
        // enable delete
        return YES;
    }

    NSString *symbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
    if (range.location == 0 && [string isEqualToString:symbol]) {
        // decimalseparator should not be first
        return NO;
    }
    NSCharacterSet *characterSet;
    NSRange separatorRange = [textField.text rangeOfString:symbol];
    if (separatorRange.location == NSNotFound) {
        if ([symbol isEqualToString:@"."]) {
            characterSet = [[NSCharacterSet characterSetWithCharactersInString:numbersPeriod] invertedSet];
        }
        else {
            characterSet = [[NSCharacterSet characterSetWithCharactersInString:numbersComma] invertedSet];              
        }
    }
    else {
        // allow 2 characters after the decimal separator
        if (range.location > (separatorRange.location + 2)) {
            return NO;
        }
        characterSet = [[NSCharacterSet characterSetWithCharactersInString:numbers] invertedSet];               
    }
    return ([[string stringByTrimmingCharactersInSet:characterSet] length] > 0);
}

您还可以使用Gamma Point solution并计算*aNumber是否为Nil,如果为Nil,则表示不是0-9的字符。或者,输入了,这样你可以只验证数字,如果输入了任何无数字字符,变量将为零。

我很想回答,因为这是我在谷歌上看到的第一个条目,排名最高的答案不允许我输入货币。
我是德国人,在德国(和许多其他国家)我们使用
作为小数分隔符

我刚刚写了一个类似的方法,这就是我现在拥有的

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if ([string length] < 1)    // non-visible characters are okay
        return YES;
    if ([string stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]].length == 0)
        return YES;
    return ([string stringByTrimmingCharactersInSet:[self.characterSet invertedSet]].length > 0);
}

我发现shouldChangeCharactersInRange将弹出式键盘、退格和“完成”按钮也搞乱了。我发现,如果我处理长度为0的字符串并允许使用控制字符,那么效果很好

我不喜欢使用NSNumberFormatter,因为它坚持用户在编辑时,数字在所有阶段都是格式良好的,如果您想在数字中保留两个小数点,直到删除错误位置的小数点,这可能会激怒您

以下是我使用的代码:

- (NSCharacterSet *)createCurrencyCharacterSet
{
    NSLocale *locale = [NSLocale currentLocale];
    NSMutableCharacterSet *currencySet = [NSMutableCharacterSet decimalDigitCharacterSet];

    [currencySet addCharactersInString:@"-"];       // negative symbol, can't find a localised version
    [currencySet addCharactersInString:[locale objectForKey:NSLocaleCurrencySymbol]];
    [currencySet addCharactersInString:[locale objectForKey:NSLocaleGroupingSeparator]];
    [currencySet addCharactersInString:[locale objectForKey:NSLocaleDecimalSeparator]];

    return [[currencySet copy] autorelease];
}
有些不愉快的代码
[[currencySet copy]autorelease]
返回一个不可变的NSCharacterSet

使用
[NSCharacterSet decimalDigitCharacterSet]
还包括等同于印度语和阿拉伯语的字符,这意味着使用这些语言的人可以使用字母表中的数字输入数字


仍然需要检查NSNumberFormatter是否能够解析用户的输入,如果不能,则发出警报;尽管如此,当只能输入合法字符时,这会带来更好的体验。

我一直看到人们在实现shouldChangeCharactersInRange时不知道如何正确确定结果字符串

以下是您如何获得新文本,如果您返回YES,将输入新文本:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {      

   NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];

   [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
   [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
   [numberFormatter setMaximumFractionDigits:2];
   [numberFormatter setMinimumFractionDigits:0];

    // Grab the contents of the text field
    NSString *text = [textField text];  

    // the appropriate decimalSeperator and currencySymbol for the current locale
    // can be found with help of the
    // NSNumberFormatter and NSLocale classes.
    NSString *decimalSeperator = numberFormatter.decimalSeparator;  
    NSString *currencySymbol = numberFormatter.currencySymbol;

    NSString *replacementText = [text stringByReplacingCharactersInRange:range withString:string];
    NSMutableString *newReplacement = [[ NSMutableString alloc ] initWithString:replacementText];

    // whenever a decimalSeperator or currencySymobol is entered, we'll just update the textField.
    // whenever other chars are entered, we'll calculate the new number and update the textField accordingly.
    // If the number can't be computed, we ignore the new input.
    NSRange decimalRange = [text rangeOfString:decimalSeperator];
    if ([string isEqualToString:decimalSeperator] == YES && 
        [text rangeOfString:decimalSeperator].length == 0) {
        [textField setText:newReplacement];
    } else if([string isEqualToString:currencySymbol] == YES&& 
              [text rangeOfString:currencySymbol].length == 0) {
        [textField setText:newReplacement];        
    } else if([newReplacement isEqualToString:currencySymbol] == YES) {
        return YES;
    }else {

        NSString *currencyGroupingSeparator = numberFormatter.currencyGroupingSeparator;

        [newReplacement replaceOccurrencesOfString:currencyGroupingSeparator withString:@"" options:NSBackwardsSearch range:NSMakeRange(0, [newReplacement length])];        
        [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

        NSNumber *number = [numberFormatter numberFromString:newReplacement];

        if([newReplacement length] == 1) {
            [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
            number = [numberFormatter numberFromString:newReplacement];
        }

        if (number == nil) { 
            [newReplacement release];
            return NO;
        }
        [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];    
        text = [numberFormatter stringFromNumber:number];
        [textField setText:text];       
    }

    [newReplacement release];

    return NO; // we return NO because we have manually edited the textField contents.
}
一旦你有了这个新的文本,很容易检查文本是否是一个有效的数字,并相应地返回是或否


请记住,如果用户试图使用带有光标键的蓝牙键盘或使用高级编辑功能(选择、剪切、粘贴)编辑字符串,则所有其他解决方案(如此处所示)都可能无法正常工作.

在找到一个处理美元货币的堆栈溢出的快速解决方案后,我重新编写了该函数,以安全地处理国际货币。此解决方案将动态验证UITextField中的用户输入,并在输入时进行更正

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

   NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string];

   //if there is empty string return YES
   if([proposedString length] == 0) {
       return YES;
   }

   //create inverted set for appripriate symbols
   NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789.,"] invertedSet];

   //if side symbols is trimmed by nonNumberSet - return NO
   if([proposedString stringByTrimmingCharactersInSet:nonNumberSet].length != [proposedString length]) {
       return NO;
   }

   //if there is more than 1 symbol of '.' or ',' return NO
   if([[proposedString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@".,"]] count] > 2) {
      return NO;
   }

   //finally check is ok, return YES
   return YES;
}

我找不到货币验证的适当实现。以下是我的变体:

    formatter = [NSNumberFormatter new];
    [formatter setNumberStyle: NSNumberFormatterCurrencyStyle];
    [formatter setLenient:YES];
    [formatter setGeneratesDecimalNumbers:YES];

我发现这是一个相对干净的方法。我没有用非美国货币测试它,但由于它使用了NSNumberFormatter的属性,我相信它应该正确处理它们

首先在某处设置格式化程序:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *replaced = [textField.text stringByReplacingCharactersInRange:range withString:string];
    NSDecimalNumber *amount = (NSDecimalNumber*) [formatter numberFromString:replaced];
    if (amount == nil) {
        // Something screwed up the parsing. Probably an alpha character.
        return NO;
    }
    // If the field is empty (the initial case) the number should be shifted to
    // start in the right most decimal place.
    short powerOf10 = 0;
    if ([textField.text isEqualToString:@""]) {
        powerOf10 = -formatter.maximumFractionDigits;
    }
    // If the edit point is to the right of the decimal point we need to do
    // some shifting.
    else if (range.location + formatter.maximumFractionDigits >= textField.text.length) {
        // If there's a range of text selected, it'll delete part of the number
        // so shift it back to the right.
        if (range.length) {
            powerOf10 = -range.length;
        }
        // Otherwise they're adding this many characters so shift left.
        else {
            powerOf10 = [string length];
        }
    }
    amount = [amount decimalNumberByMultiplyingByPowerOf10:powerOf10];

    // Replace the value and then cancel this change.
    textField.text = [formatter stringFromNumber:amount];
    return NO;
}
使用格式化程序解析和重新格式化输入。它还处理数字添加和删除时的数字移位


负数呢?您不想在反转的有效集合中添加“-”吗?如果用户想要删除输入的数字呢?除了禁用退格键(如ashish所述)之外,上述代码也可以工作。如果用户连接了蓝牙键盘,则不会有帮助,因为他可以输入他喜欢的内容。这太棒了,谢谢。刚刚有一位客户抱怨小数点后两位以上:)这是迄今为止更全面的解决方案。我建议大家接受这个答案。谢谢Brian,你有没有注意到你的代码不能在0之后输入
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

   NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string];

   //if there is empty string return YES
   if([proposedString length] == 0) {
       return YES;
   }

   //create inverted set for appripriate symbols
   NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789.,"] invertedSet];

   //if side symbols is trimmed by nonNumberSet - return NO
   if([proposedString stringByTrimmingCharactersInSet:nonNumberSet].length != [proposedString length]) {
       return NO;
   }

   //if there is more than 1 symbol of '.' or ',' return NO
   if([[proposedString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@".,"]] count] > 2) {
      return NO;
   }

   //finally check is ok, return YES
   return YES;
}
    formatter = [NSNumberFormatter new];
    [formatter setNumberStyle: NSNumberFormatterCurrencyStyle];
    [formatter setLenient:YES];
    [formatter setGeneratesDecimalNumbers:YES];
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *replaced = [textField.text stringByReplacingCharactersInRange:range withString:string];
    NSDecimalNumber *amount = (NSDecimalNumber*) [formatter numberFromString:replaced];
    if (amount == nil) {
        // Something screwed up the parsing. Probably an alpha character.
        return NO;
    }
    // If the field is empty (the initial case) the number should be shifted to
    // start in the right most decimal place.
    short powerOf10 = 0;
    if ([textField.text isEqualToString:@""]) {
        powerOf10 = -formatter.maximumFractionDigits;
    }
    // If the edit point is to the right of the decimal point we need to do
    // some shifting.
    else if (range.location + formatter.maximumFractionDigits >= textField.text.length) {
        // If there's a range of text selected, it'll delete part of the number
        // so shift it back to the right.
        if (range.length) {
            powerOf10 = -range.length;
        }
        // Otherwise they're adding this many characters so shift left.
        else {
            powerOf10 = [string length];
        }
    }
    amount = [amount decimalNumberByMultiplyingByPowerOf10:powerOf10];

    // Replace the value and then cancel this change.
    textField.text = [formatter stringFromNumber:amount];
    return NO;
}