objective c - Verifique que una entrada a UITextField sea numérica solamente
objective-c cocoa-touch (22)
Acepte valores decimales en campos de texto con punto único (.) Que funcione con iPad y iPhone en 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
}
}
}
¿Cómo valido la entrada de cadena a un UITextField
? Quiero verificar que la cadena sea numérica, incluidos los puntos decimales.
Aquí hay algunas líneas simples que combinan la respuesta de Peter Lewis anterior ( Verifique que una entrada a UITextField sea numérica solamente ) con 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]
En Swift 4:
let formatString = "12345"
if let number = Decimal(string:formatString){
print("String contains only number")
}
else{
print("String doesn''t contains only number")
}
Esta respuesta usa NSFormatter como se dijo anteriormente. Echale un vistazo:
@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
Espero que esto ayude a alguien. =)
Esto cubre: control de parte decimal (incluyendo el número de decimales permitido), control de copiar / pegar, separadores internacionales.
Pasos:
Asegúrese de que su controlador de vista se hereda de UITextFieldDelegate
clase MyViewController: UIViewController, UITextFieldDelegate {...
En viewDidLoad, configure su delegado de control en uno mismo:
anular func viewDidLoad () {super.viewDidLoad (); yourTextField.delegate = self}
Implemente el siguiente método y actualice la constante "decsAllowed" con la cantidad deseada de decimales o 0 si desea un número natural.
Swift 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
}
Si luego necesita convertir esa cadena en un número de manera segura, puede usar el tipo de conversión Double (yourstring) o Int (yourstring), o la forma más académica:
let formatter = NumberFormatter()
let theNumber: NSNumber = formatter.number(from: yourTextField.text)!
Hay algunas maneras en que podrías hacer esto:
- Use el método NSNumberFormatter numberFromString :. Esto devolverá un NSNumber si puede analizar la cadena correctamente, o
nil
si no puede. - Use NSScanner
- Pele cualquier carácter no numérico y vea si la cuerda todavía coincide
- Usa una expresión regular
IMO, usando algo como -[NSString doubleValue]
no sería la mejor opción porque @"0.0"
y @"abc"
tendrán un doubleValue de 0. Todos los métodos value devuelven 0 si no pueden convertir la cadena correctamente, por lo que sería difícil distinguir entre una cadena legítima de @"0"
y una cadena no válida. Algo así como la función strtol
de C tendría el mismo problema.
Creo que usar NSNumberFormatter sería la mejor opción, ya que tiene en cuenta la configuración regional (es decir, el número @"1,23"
en Europa, frente a @"1.23"
en EE. UU.).
Hola, tuve exactamente el mismo problema y no veo la respuesta que utilicé publicada, así que aquí está.
Creé y conecté mi campo de texto a través de IB. Cuando lo conecté a mi código mediante Control + Drag, elegí Acción, luego seleccioné el evento Editing Changed. Esto activa el método en cada entrada de personaje. Puede usar un evento diferente para adaptarse.
Después, utilicé este código simple para reemplazar el texto. Tenga en cuenta que creé mi propio juego de caracteres para incluir el carácter y los números de decimales / períodos. Básicamente separa la cadena en los caracteres no válidos, luego los vuelve a juntar con una cadena vacía.
- (IBAction)myTextFieldEditingChangedMethod:(UITextField *)sender {
NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@".0123456789"];
NSCharacterSet *invalidCharacterSet = validCharacterSet.invertedSet;
sender.text = [[sender.text componentsSeparatedByCharactersInSet:invalidCharacterSet] componentsJoinedByString:@""];
}
Créditos: elimine todos los números de NSString
No tan elegante, pero simple :)
- (BOOL) isNumber: (NSString*)input
{
return [input doubleValue] != 0 || [input isEqualToString:@"0"] || [input isEqualToString:@"0.0"];
}
OMI: la mejor manera de lograr su objetivo es mostrar un teclado numérico en lugar del teclado normal. Esto restringe qué claves están disponibles para el usuario. Esto alivia la necesidad de hacer la validación y, lo que es más importante, evita que el usuario cometa un error. El teclado numérico también es mucho más agradable para ingresar números porque las teclas son sustancialmente más grandes.
En el constructor de interfaces, seleccione UITextField, vaya al Inspector de atributos y cambie el "Tipo de teclado" a "Panel decimal".
Eso hará que el teclado se vea así:
Lo único que queda por hacer es garantizar que el usuario no ingrese dos decimales. Puedes hacer esto mientras están editando. Agregue el siguiente código a su controlador de vista. Este código elimina un segundo decimal tan pronto como se ingresa. Al usuario le parece que el segundo decimal nunca apareció en primer lugar.
- (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];
}
}
Para la prueba de enteros será:
- (BOOL) isIntegerNumber: (NSString*)input
{
return [input integerValue] != 0 || [input isEqualToString:@"0"];
}
Para ser más internacional (y no solo estadounidense ;-)) simplemente reemplace en el código anterior por
-(NSNumber *) getNumber
{
NSString* localeIdentifier = [[NSLocale autoupdatingCurrentLocale] localeIdentifier];
NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: localeIdentifier] ;
return [self getNumberWithLocale: [l_en autorelease] ];
}
Puedes hacerlo en unas pocas líneas como esta:
BOOL valid;
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:myInputField.text];
valid = [alphaNums isSupersetOfSet:inStringSet];
if (!valid) // Not numeric
- esto es para validar la entrada es solo caracteres numéricos. Mire la documentación para NSCharacterSet
para las otras opciones. Puede usar characterSetWithCharactersInString para especificar cualquier conjunto de caracteres de entrada válidos.
Puedes usar doubleValue de tu cadena como
NSString *string=@"1.22";
double a=[string doubleValue];
Creo que esto devolverá un valor de 0.0 si la cadena no es válida (podría arrojar una excepción, en cuyo caso puede simplemente atraparla, los documentos dicen 0.0 tho). más información here
Quería un campo de texto que solo permitiera enteros. Aquí es a lo que terminé (usando información de aquí y de otros lugares):
Crear formateador de números enteros (en UIApplicationDelegate para que pueda ser reutilizado):
@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;
}
Use el filtro en 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;
}
Si desea que un usuario solo permita ingresar números, puede hacer que su ViewController implemente parte de UITextFieldDelegate y defina este método:
- (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];
}
Probablemente haya formas más eficientes, pero considero que esta es una forma muy conveniente . Y el método debe ser fácilmente adaptable para validar dobles o lo que sea: simplemente use scanDouble: o similar.
Tarde en el juego, pero aquí utilizo una pequeña categoría que da cuenta de los lugares decimales y el símbolo local que se usa. enlace a su esencia here
@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
Uso este código en mi aplicación Mac, el mismo o similar debería funcionar con el iPhone. Se basa en las expresiones regulares de RegexKitLite y convierte el texto en rojo cuando no es válido.
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]];
}
}
Viejo hilo, pero vale la pena mencionar que Apple presentó NSRegularExpression
en iOS 4.0. (Tomando la expresión regular de la respuesta de Pedro)
// 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!
}
Sugiero almacenar la instancia NSRegularExpression
alguna parte.
#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;
}
#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;
}
- (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;
}
@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;
}
}