Jak sprawdzić poprawność danych wejściowych ciągu w pliku UITextField
? Chcę sprawdzić, czy ciąg jest liczbą, w tym kropkami dziesiętnymi.
Jak sprawdzić poprawność danych wejściowych ciągu w pliku UITextField
? Chcę sprawdzić, czy ciąg jest liczbą, w tym kropkami dziesiętnymi.
Odpowiedzi:
Używam tego kodu w mojej aplikacji na Maca, ten sam lub podobny powinien działać z iPhonem. Opiera się na wyrażeniach regularnych RegexKitLite i zmienia kolor tekstu na czerwony, gdy jest nieprawidłowy.
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]];
}
}
(?:|0|[1-9]\\d*)(?:\\.\\d*)
aby zobaczyć, co to oznacza. Zobacz także Regex Wikipedia
Możesz to zrobić w kilku linijkach w ten sposób:
BOOL valid;
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:myInputField.text];
valid = [alphaNums isSupersetOfSet:inStringSet];
if (!valid) // Not numeric
- służy do sprawdzania poprawności danych wejściowych tylko znaków numerycznych. Zapoznaj się z dokumentacją dotyczącą NSCharacterSet
innych opcji. Możesz użyć characterSetWithCharactersInString, aby określić dowolny zestaw prawidłowych znaków wejściowych.
Możesz to zrobić na kilka sposobów:
nil
nie może.IMO, użycie czegoś takiego jak -[NSString doubleValue]
nie byłoby najlepszą opcją, ponieważ oba @"0.0"
i @"abc"
będą miały doubleValue równe 0. Wszystkie metody * value zwracają 0, jeśli nie są w stanie poprawnie przekonwertować ciągu, więc byłoby trudno rozróżnić prawidłowy ciąg @"0"
i niepoprawny ciąg. Coś w rodzaju strtol
funkcji C miałoby ten sam problem.
Myślę, że użycie NSNumberFormatter byłoby najlepszą opcją, ponieważ bierze pod uwagę lokalizację (tj. Liczbę @"1,23"
w Europie, w porównaniu @"1.23"
z USA).
NSNumberFormatter * f = [[NSNumberFormatter alloc] init]; NSNumber * n = [f numberFromString:@"34jfkjdskj80"]; NSLog(@"N: %@", n);
NSScanner
przykład NSNumberFormatter
, bierze pod uwagę ustawienia regionalne, pod warunkiem, że używasz setLocale:
na obiekcie skanera (możesz na przykład podać [NSLocale currentLocale]
).
Jeśli chcesz, aby użytkownik mógł wprowadzać tylko cyfry, możesz sprawić, by ViewController implementował część UITextFieldDelegate i zdefiniował tę metodę:
- (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];
}
Prawdopodobnie są bardziej wydajne sposoby, ale uważam, że jest to całkiem wygodny sposób. Metoda powinna być łatwa do dostosowania do walidacji podwójnych lub czegokolwiek innego: po prostu użyj scanDouble: lub podobnego.
#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;
}
Oto kilka jednowierszowych, które łączą powyższą odpowiedź Petera Lewisa ( Sprawdź, czy dane wejściowe do UITextField są tylko liczbowe ) z 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]
Dla testu liczb całkowitych będzie to:
- (BOOL) isIntegerNumber: (NSString*)input
{
return [input integerValue] != 0 || [input isEqualToString:@"0"];
}
Możesz użyć doubleValue swojego ciągu, na przykład
NSString *string=@"1.22";
double a=[string doubleValue];
Myślę, że zwróci to wartość 0,0, jeśli łańcuch jest nieprawidłowy (może to spowodować zgłoszenie wyjątku, w którym to przypadku można go po prostu złapać, dokumentacja mówi, że jest to 0,0). więcej informacji tutaj
Cześć, miałem dokładnie ten sam problem i nie widzę odpowiedzi, której użyłem, opublikowanej, więc oto jest.
Stworzyłem i połączyłem swoje pole tekstowe przez IB. Kiedy połączyłem go z moim kodem za pomocą Control + Drag, wybrałem Action, a następnie wybrałem zdarzenie Editing Changed. Spowoduje to wyzwolenie metody przy każdym wpisie znaku. Możesz użyć innego zdarzenia.
Następnie użyłem tego prostego kodu, aby zastąpić tekst. Zwróć uwagę, że stworzyłem własny zestaw znaków zawierający znaki dziesiętne / kropki i liczby. Zasadniczo oddziela ciąg od nieprawidłowych znaków, a następnie łączy je ponownie z pustym ciągiem.
- (IBAction)myTextFieldEditingChangedMethod:(UITextField *)sender {
NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@".0123456789"];
NSCharacterSet *invalidCharacterSet = validCharacterSet.invertedSet;
sender.text = [[sender.text componentsSeparatedByCharactersInSet:invalidCharacterSet] componentsJoinedByString:@""];
}
Spóźniona gra, ale tutaj przydatna mała kategoria, której używam, która uwzględnia miejsca dziesiętne i używany do tego lokalny symbol. link do jego istoty tutaj
@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
- (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;
}
IMO najlepszym sposobem na osiągnięcie celu jest wyświetlanie klawiatury numerycznej zamiast zwykłej klawiatury. Ogranicza to, które klucze są dostępne dla użytkownika. Zmniejsza to potrzebę przeprowadzania walidacji, a co ważniejsze, zapobiega popełnieniu błędu przez użytkownika. Klawiatura numeryczna jest również znacznie przyjemniejsza do wprowadzania cyfr, ponieważ klawisze są znacznie większe.
W konstruktorze interfejsu wybierz UITextField, przejdź do Inspektora atrybutów i zmień „Typ klawiatury” na „Pad dziesiętny”.
Dzięki temu klawiatura będzie wyglądać tak:
Pozostaje tylko upewnić się, że użytkownik nie wprowadza do dwóch miejsc po przecinku. Możesz to zrobić podczas edycji. Dodaj następujący kod do kontrolera widoku. Ten kod usuwa drugie miejsce po przecinku, gdy tylko zostanie wprowadzony. Wydaje się użytkownikowi, że 2. miejsce po przecinku nigdy nie pojawiło się na pierwszym miejscu.
- (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];
}
}
@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;
}
}
Stary wątek, ale warto wspomnieć, że Apple wprowadziło NSRegularExpression
iOS 4.0. (Biorąc wyrażenie regularne z odpowiedzi Piotra)
// 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!
}
Proponuję NSRegularExpression
gdzieś przechowywać instancję.
Chciałem mieć pole tekstowe, które dopuszcza tylko liczby całkowite. Oto, na czym skończyłem (używając informacji z tego miejsca i gdzie indziej):
Utwórz program formatujący liczby całkowite (w UIApplicationDelegate, aby można go było ponownie wykorzystać):
@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;
}
Użyj filtra w 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;
}
Nie tak elegancko, ale prosto :)
- (BOOL) isNumber: (NSString*)input
{
return [input doubleValue] != 0 || [input isEqualToString:@"0"] || [input isEqualToString:@"0.0"];
}
Akceptuj wartości dziesiętne w polach tekstowych z pojedynczą (.) Kropką na iPadzie i iPhonie w Swift 3
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
}
}
}
Aby być bardziej międzynarodowym (i nie tylko w kolorze amerykańskim ;-)) po prostu zastąp w powyższym kodzie przez
-(NSNumber *) getNumber
{
NSString* localeIdentifier = [[NSLocale autoupdatingCurrentLocale] localeIdentifier];
NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: localeIdentifier] ;
return [self getNumberWithLocale: [l_en autorelease] ];
}
Ta odpowiedź używa NSFormatter, jak wspomniano wcześniej. Sprawdź to:
@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
Mam nadzieję, że to komuś pomoże. =)
#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;
}
W Swift 4:
let formatString = "12345"
if let number = Decimal(string:formatString){
print("String contains only number")
}
else{
print("String doesn't contains only number")
}
Obejmuje to: kontrolę części dziesiętnej (w tym dozwoloną liczbę miejsc po przecinku), kontrolę kopiowania / wklejania, separatory międzynarodowe.
Kroki:
Upewnij się, że kontroler widoku dziedziczy po UITextFieldDelegate
klasa MyViewController: UIViewController, UITextFieldDelegate {...
W viewDidLoad ustaw delegata kontroli na siebie:
nadpisz func viewDidLoad () {super.viewDidLoad (); yourTextField.delegate = self}
Zaimplementuj następującą metodę i zaktualizuj stałą „decsAllowed” o żądaną liczbę miejsc po przecinku lub 0, jeśli chcesz uzyskać liczbę naturalną.
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
}
Jeśli później chcesz bezpiecznie przekonwertować ten ciąg na liczbę, możesz po prostu użyć rzutowania typu Double (yourstring) lub Int (yourstring) lub w bardziej akademicki sposób:
let formatter = NumberFormatter()
let theNumber: NSNumber = formatter.number(from: yourTextField.text)!
+ (BOOL) TextIsValidValue:(NSString*)newText:(double)&value:
...