UITextFieldへの入力が数値のみであることを確認してください


回答:


35

私はこのコードをMacアプリで使用していますが、iPhoneでも同じまたは類似のコードが機能するはずです。これはRegexKitLiteの正規表現に基づいており、無効になるとテキストが赤に変わります。

static bool TextIsValidValue( NSString* newText, double &value )
{
    bool result = false;

    if ( [newText isMatchedByRegex:@"^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$"] ) {
        result = true;
        value = [newText doubleValue];
    }
    return result;
}

- (IBAction) doTextChanged:(id)sender;
{
    double value;
    if ( TextIsValidValue( [i_pause stringValue], value ) ) {
        [i_pause setTextColor:[NSColor blackColor]];
        // do something with the value
    } else {
        [i_pause setTextColor:[NSColor redColor]];
    }
}

7
はい、これはひどく古い答えです、私は知っていますが、静的メソッドは次のように宣言されていると思いました:+ (BOOL) TextIsValidValue:(NSString*)newText:(double)&value:...
RCIX 2011

7
TextIsValidValueは静的C関数です。これは、ファイルに対してローカルであり、オブジェクトの一部ではないことを意味します。あなた(@RCIX)は、C ++の静的メソッドに似ており、静的C関数(または静的変数)とはまったく異なる概念であるオブジェクトメソッドについて説明しています。
ピーターNルイス

式は空の文字列(数値ではありません)と一致します。
Nikolai Ruhe 2012

一般に、入力用の数値を照合するには、空の文字列を許可する必要があります。許可しない場合、たとえば、ユーザーは「1 <delete> 2」と入力できません。
ピーターNルイス

6
正規表現とは何か、またはそれらがどのように機能するかを知らない開発者の場合は、この正規表現デコーダーのウェスバイトにアクセスし、コピー/貼り付け(?:|0|[1-9]\\d*)(?:\\.\\d*)して、その意味を確認してください。Regex Wikipedia
Honey

117

あなたはこのように数行でそれを行うことができます:

BOOL valid;
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:myInputField.text];
valid = [alphaNums isSupersetOfSet:inStringSet];    
if (!valid) // Not numeric

-これは、入力が数値文字のみであることを検証するためのものです。NSCharacterSet他のオプションについては、ドキュメントを参照してください。characterSetWithCharactersInStringを使用して、有効な入力文字の任意のセットを指定できます。


22
この回答は、二重または句読点をチェックしません
zambono 2011年

72

これを行うには、いくつかの方法があります。

  1. NSNumberFormatterのnumberFromString:メソッドを使用します。これは、文字列を正しく解析nilできる場合、またはできない場合にNSNumberを返します。
  2. NSScannerを使用する
  3. 数字以外の文字をすべて削除し、文字列がまだ一致するかどうかを確認します
  4. 正規表現を使用する

IMO、のようなものを使用すると、-[NSString doubleValue]両方のための最良の選択肢ではないでしょう@"0.0"し、@"abc"それらが適切に文字列を変換することができないなら、Aを区別することは困難であるので、0 *値メソッドののdoubleValueを持つことになりますが、すべて、0を返しますの正当な文字列@"0"と無効な文字列。Cのstrtol関数のようなものでも同じ問題が発生します。

NSNumberFormatterを使用するのが最良のオプションだと思います。これは、ロケールが考慮されるためです(つまり、@"1,23"ヨーロッパと@"1.23"米国の数値)。


うーん、NSNumberFormatterのオプションを間違って設定している必要があります。文字列「34jfkjdskj80」を使用してnumberFromStringを使用すると、数値3480が返されます。nilを返すのではなく、文字を削除するだけのようです。
Tony Eichelberger

5
:私のために:@Tonyええため、私は次のログ「(ヌル)N」、あなたは何をやっているかわからないNSNumberFormatter * f = [[NSNumberFormatter alloc] init]; NSNumber * n = [f numberFromString:@"34jfkjdskj80"]; NSLog(@"N: %@", n);
デイヴ・デロング

2
これは少し古いですが、誰かがこれを読んでいる場合は、スキャナーオブジェクトで使用する場合、文字列を解析するときにNSScanner、のようNSNumberFormatterにロケールが考慮されることに注意する必要があると思いsetLocale:ました(たとえば、[NSLocale currentLocale])。
dreamlax 2010年

1
「戦争と平和」を読む人もいます。他の人は「モービーディック」を好みます。私自身、Stack Overflowデータセットをプルダウンし、Daveの回答で質問を除外して、楽しんでいると思います。
BP。

1
@MarkAmeryはい、その動作に頼ることができます。文書化されていないかもしれませんが、それは長年にわたってどのように動作してきたかであり、バイナリ互換性の観点からは、変更することは不可能です。
Dave DeLong 2013

19

ユーザーに数字の入力のみを許可する場合は、ViewControllerにUITextFieldDelegateの一部を実装させ、次のメソッドを定義できます。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
  NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string];

  // The user deleting all input is perfectly acceptable.
  if ([resultingString length] == 0) {
    return true;
  }

  NSInteger holder;

  NSScanner *scan = [NSScanner scannerWithString: resultingString];

  return [scan scanInteger: &holder] && [scan isAtEnd];
}

おそらくもっと効率的な方法がありますが、これはかなり便利な方法だと思います。また、このメソッドは、doubleなどの検証に簡単に適応できる必要があります。scanDouble:などを使用するだけです。


13
#pragma mark - UItextfield Delegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if ([string isEqualToString:@"("]||[string isEqualToString:@")"]) {
        return TRUE;
    }

    NSLog(@"Range ==%d  ,%d",range.length,range.location);
    //NSRange *CURRANGE = [NSString  rangeOfString:string];

    if (range.location == 0 && range.length == 0) {
        if ([string isEqualToString:@"+"]) {
            return TRUE;
        }
    }
    return [self isNumeric:string];
}

-(BOOL)isNumeric:(NSString*)inputString{
    BOOL isValid = NO;
    NSCharacterSet *alphaNumbersSet = [NSCharacterSet decimalDigitCharacterSet];
    NSCharacterSet *stringSet = [NSCharacterSet characterSetWithCharactersInString:inputString];
    isValid = [alphaNumbersSet isSupersetOfSet:stringSet];
    return isValid;
}

11

上記のPeterLewisの回答(UITextFieldへの入力が数値のみであることを確認してください)とNSPredicatesを組み合わせたワンライナーをいくつか示します。

    #define REGEX_FOR_NUMBERS   @"^([+-]?)(?:|0|[1-9]\\d*)(?:\\.\\d*)?$"
    #define REGEX_FOR_INTEGERS  @"^([+-]?)(?:|0|[1-9]\\d*)?$"
    #define IS_A_NUMBER(string) [[NSPredicate predicateWithFormat:@"SELF MATCHES %@", REGEX_FOR_NUMBERS] evaluateWithObject:string]
    #define IS_AN_INTEGER(string) [[NSPredicate predicateWithFormat:@"SELF MATCHES %@", REGEX_FOR_INTEGERS] evaluateWithObject:string]

私がそれについてもっと学ぶことができるところから私にリンクを提供してください。
Smit Saraiya 2016年

4

整数テストの場合は次のようになります。

- (BOOL) isIntegerNumber: (NSString*)input
{
    return [input integerValue] != 0 || [input isEqualToString:@"0"];
}

良い答えですが、それでもこのアプローチの問題は、数値と見なされる入力値「232asdfsadf」を持つことです。
whoami 2014

integerValue(文字列に再変換)を元の文字列と長さ比較して、「123aoenuthr」が整数と見なされないようにすることができます。
Michael

3

次のように文字列のdoubleValueを使用できます

NSString *string=@"1.22";
double a=[string doubleValue];

文字列が無効な場合、これは0.0として返されると思います(例外がスローされる可能性があります。その場合は、キャッチできます。ドキュメントには0.0 thoと記載されています)。詳細はこちら


また、ライブラリ関数を使用することは、通常、独自の関数をロールするよりも優れています。この場合、他のカルチャでは小数点にコンマを使用し、おそらくCocoaライブラリがそれを処理できます。
kibibu 2009

文字通りのフロート等式比較を行うことは言うまでもなく悪い習慣です
M. Ryan

3

こんにちは、まったく同じ問題があり、私が使用した回答が投稿されていないので、ここにあります。

IBを介してテキストフィールドを作成して接続しました。Control + Dragを介してコードに接続したときに、[アクション]を選択してから、[変更された編集]イベントを選択しました。これにより、各文字エントリでメソッドがトリガーされます。それに合わせて別のイベントを使用できます。

その後、この単純なコードを使用してテキストを置き換えました。10進数/ピリオド文字と数字を含む独自の文字セットを作成したことに注意してください。基本的に、無効な文字の文字列を区切り、空の文字列で再結合します。

- (IBAction)myTextFieldEditingChangedMethod:(UITextField *)sender {
        NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@".0123456789"];
        NSCharacterSet *invalidCharacterSet = validCharacterSet.invertedSet;
        sender.text = [[sender.text componentsSeparatedByCharactersInSet:invalidCharacterSet] componentsJoinedByString:@""];
}

クレジット: NSStringから数字以外のすべてを削除します


負の数(-)?
CMVR 2013

3

ゲームの後半ですが、ここでは、小数点以下の桁数とそれに使用されるローカル記号を説明する便利な小さなカテゴリを使用しています。ここにその要点へのリンク

@interface NSString (Extension)

- (BOOL) isAnEmail;
- (BOOL) isNumeric;

@end

@implementation NSString (Extension)

/**
 *  Determines if the current string is a valid email address.
 *
 *  @return BOOL - True if the string is a valid email address.
 */

- (BOOL) isAnEmail
{
    NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];

    return [emailTest evaluateWithObject:self];
}

/**
 *  Determines if the current NSString is numeric or not. It also accounts for the localised (Germany for example use "," instead of ".") decimal point and includes these as a valid number.
 *
 *  @return BOOL - True if the string is numeric.
 */

- (BOOL) isNumeric
{
    NSString *localDecimalSymbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
    NSMutableCharacterSet *decimalCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:localDecimalSymbol];
    [decimalCharacterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];

    NSCharacterSet* nonNumbers = [decimalCharacterSet invertedSet];
    NSRange r = [self rangeOfCharacterFromSet: nonNumbers];

    if (r.location == NSNotFound)
    {
        // check to see how many times the decimal symbol appears in the string. It should only appear once for the number to be numeric.
        int numberOfOccurances = [[self componentsSeparatedByString:localDecimalSymbol] count]-1;
        return (numberOfOccurances > 1) ? NO : YES;
    }
    else return NO;
}

@end

alphanumericCharacterSetをisNumericのdecimalDigitCharacterSetにするべきではありませんか?これが私の使い方です。
アンドレイラドゥレスク2014

ない「A」の結果を得るISNUMERIC YES @仕事、が、それは数ではありません
Gank

3
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if(string.length > 0)
    {
        NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
        NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:string];

        BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField];
        return stringIsValid;
    }
    return YES;
}

3

IMOは、目標を達成するための最良の方法は、通常のキーボードではなく数字キーボードを表示することです。これにより、ユーザーが使用できるキーが制限されます。これにより、検証を行う必要がなくなり、さらに重要なことに、ユーザーがミスを犯すのを防ぐことができます。キーが大幅に大きいため、テンキーも数字の入力に適しています。

Interface BuilderでUITextFieldを選択し、Attributes Inspectorに移動して、「KeyboardType」を「DecimalPad」に変更します。

ここに画像の説明を入力してください

これにより、キーボードは次のようになります。

ここに画像の説明を入力してください

あとは、ユーザーが小数点以下2桁で入力しないようにするだけです。彼らが編集している間にこれを行うことができます。次のコードをViewControllerに追加します。このコードは、入力されるとすぐに小数点以下第2位を削除します。ユーザーには、小数点以下第2位が最初から表示されていないように見えます。

- (void)viewDidLoad
{
  [super viewDidLoad];

  [self.textField addTarget:self
                    action:@selector(textFieldDidChange:)
           forControlEvents:UIControlEventEditingChanged];
}

- (void)textFieldDidChange:(UITextField *)textField
{
  NSString *text = textField.text;
  NSRange range = [text rangeOfString:@"."];

  if (range.location != NSNotFound &&
      [text hasSuffix:@"."] &&
      range.location != (text.length - 1))
  {
    // There's more than one decimal
    textField.text = [text substringToIndex:text.length - 1];
  }
}

1
コピー忘れる&能力を貼り付けないでください-あなたのアプローチは、この場合には失敗した
slxl

1
これはすべての場合に対応しているわけではありません。ユーザーは、テキストの貼り付けをコピーするか、Bluetoothキーボードを使用できます。
Bean

2
@property (strong) NSNumberFormatter *numberFormatter;
@property (strong) NSString *oldStringValue;

- (void)awakeFromNib 
{
  [super awakeFromNib];
  self.numberFormatter = [[NSNumberFormatter alloc] init];
  self.oldStringValue = self.stringValue;
  [self setDelegate:self];
}

- (void)controlTextDidChange:(NSNotification *)obj
{
  NSNumber *number = [self.numberFormatter numberFromString:self.stringValue];
  if (number) {
    self.oldStringValue = self.stringValue;
  } else {
    self.stringValue = self.oldStringValue;
  }
}

2

古いスレッドですが、AppleがiOS4.0で導入NSRegularExpressionしたことは言及する価値があります。(ピーターの応答から正規表現を取得)

// Look for 0-n digits from start to finish
NSRegularExpression *noFunnyStuff = [NSRegularExpression regularExpressionWithPattern:@"^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$" options:0 error:nil];

// There should be just one match
if ([noFunnyStuff numberOfMatchesInString:<#theString#> options:0 range:NSMakeRange(0, <#theString#>.length)] == 1)
{
    // Yay, digits!
}

NSRegularExpressionインスタンスをどこかに保存することをお勧めします。


1

整数のみを許可するテキストフィールドが必要でした。これが私が最終的に得たものです(ここや他の場所からの情報を使用して):

整数フォーマッターを作成します(再利用できるようにUIApplicationDelegateで):

@property (nonatomic, retain) NSNumberFormatter *integerNumberFormatter;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Create and configure an NSNumberFormatter for integers
    integerNumberFormatter = [[NSNumberFormatter alloc] init];
    [integerNumberFormatter setMaximumFractionDigits:0];

    return YES;
}

UITextFieldDelegateでフィルターを使用します。

@interface MyTableViewController : UITableViewController <UITextFieldDelegate> {
    ictAppDelegate *appDelegate;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // Make sure the proposed string is a number
    NSNumberFormatter *inf = [appDelegate integerNumberFormatter];
    NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    NSNumber *proposedNumber = [inf numberFromString:proposedString];
    if (proposedNumber) {
        // Make sure the proposed number is an integer
        NSString *integerString = [inf stringFromNumber:proposedNumber];
        if ([integerString isEqualToString:proposedString]) {
            // proposed string is an integer
            return YES;
        }
    }

    // Warn the user we're rejecting the change
    AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
    return NO;
}

1

それほどエレガントではありませんが、シンプルです:)

- (BOOL) isNumber: (NSString*)input
{
    return [input doubleValue] != 0 || [input isEqualToString:@"0"] || [input isEqualToString:@"0.0"];
}

1
このソリューションは、0.00のような無限のゼロでは機能しません。だから私はそれを使用している人々を提案しません
Vinh 2014

1

Swift 3のiPadおよびiPhoneで機能する単一(。)ドットのテキストフィールドで10進値を受け入れる

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted

        let components = string.components(separatedBy: inverseSet)

        let filtered = components.joined(separator: "")

        if filtered == string {
            return true
        } else {
            if string == "." {
                let countdots = textField.text!.components(separatedBy:".").count - 1
                if countdots == 0 {
                    return true
                }else{
                    if countdots > 0 && string == "." {
                        return false
                    } else {
                        return true
                    }
                }
            }else{
                return false
            }
        }
    }

0

より国際的にするために(そして米国の色だけでなく;-))上記のコードを次のように置き換えるだけです

-(NSNumber *) getNumber
{
  NSString* localeIdentifier = [[NSLocale autoupdatingCurrentLocale] localeIdentifier];
  NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: localeIdentifier] ;
  return [self getNumberWithLocale: [l_en autorelease] ];
}

0

この回答では、前述のようにNSFormatterを使用しています。見てみな:

@interface NSString (NSNumber)
- (BOOL) isNumberWithLocale:(NSLocale *) stringLocale;  
- (BOOL) isNumber;
- (NSNumber *) getNumber; 
- (NSNumber *) getNumberWithLocale:(NSLocale*) stringLocale;
@end

@implementation NSString (NSNumber)
- (BOOL) isNumberWithLocale:(NSLocale *) stringLocale
{
    return [self getNumberWithLocale:stringLocale] != nil;
}
- (BOOL) isNumber
{
    return [ self getNumber ] != nil;
}
- (NSNumber *) getNumber
{
    NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: @"en_US"] ;  
    return [self getNumberWithLocale: [l_en autorelease] ];
}

- (NSNumber *) getNumberWithLocale:(NSLocale*) stringLocale
{
    NSNumberFormatter *formatter = [[ [ NSNumberFormatter alloc ] init ] autorelease];
    [formatter setLocale: stringLocale ];
    return [ formatter numberFromString:self ]; 
}
@end

私はそれが誰かを助けることを願っています。=)


0
   #import "NSString+Extension.h"

//@interface NSString (Extension)
//
//- (BOOL) isAnEmail;
//- (BOOL) isNumeric;
//
//@end

@implementation NSString (Extension)
 - (BOOL) isNumeric
    {
        NSString *emailRegex = @"[0-9]+";
        NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];

        return [emailTest evaluateWithObject:self];

    //    NSString *localDecimalSymbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
    //    NSMutableCharacterSet *decimalCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:localDecimalSymbol];
    //    [decimalCharacterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];
    //    
    //    NSCharacterSet* nonNumbers = [decimalCharacterSet invertedSet];
    //    NSRange r = [self rangeOfCharacterFromSet: nonNumbers];
    //    
    //    if (r.location == NSNotFound)
    //    {
    //        // check to see how many times the decimal symbol appears in the string. It should only appear once for the number to be numeric.
    //        int numberOfOccurances = [[self componentsSeparatedByString:localDecimalSymbol] count]-1;
    //        return (numberOfOccurances > 1) ? NO : YES;
    //    }
    //    else return NO;
    }

0

Swift 4:

let formatString = "12345"
if let number = Decimal(string:formatString){

    print("String contains only number")
}
else{
    print("String doesn't contains only number")
}

0

これには、小数部の制御(許可される小数の数を含む)、コピー/貼り付けの制御、国際区切り記号が含まれます。

手順:

  1. ビューコントローラがUITextFieldDelegateから継承していることを確認してください

    クラスMyViewController:UIViewController、UITextFieldDelegate {..。

  2. viewDidLoadで、コントロールデリゲートをselfに設定します。

    func viewDidLoad(){super.viewDidLoad();をオーバーライドします。yourTextField.delegate = self}

  3. 次のメソッドを実装し、「decsAllowed」定数を必要な小数で更新します。自然数が必要な場合は0を更新します。

スウィフト4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let decsAllowed: Int = 2
    let candidateText = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
    let decSeparator: String = NumberFormatter().decimalSeparator!;

    let splitted = candidateText.components(separatedBy: decSeparator)
    let decSeparatorsFound = splitted.count - 1
    let decimalPart = decSeparatorsFound > 0 ? splitted.last! : ""
    let decimalPartCount = decimalPart.characters.count

    let characterSet = NSMutableCharacterSet.decimalDigit()
    if decsAllowed > 0 {characterSet.addCharacters(in: decSeparator)}

    let valid = characterSet.isSuperset(of: CharacterSet(charactersIn: candidateText)) &&
                decSeparatorsFound <= 1 &&
                decsAllowed >= decimalPartCount

    return valid
}

その後、その文字列を安全に数値に変換する必要がある場合は、Double(yourstring)またはInt(yourstring)型キャスト、またはよりアカデミックな方法を使用できます。

let formatter = NumberFormatter()
let theNumber: NSNumber = formatter.number(from: yourTextField.text)!
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.