objective-c nsstring

objective c - Eliminar todos los números de NSString



objective-c (20)

Tengo un NSString (número de teléfono) con algunos paréntesis y guiones, ya que algunos números de teléfono están formateados. ¿Cómo eliminaría todos los caracteres excepto los números de la cadena?


Swift 3

let notNumberCharacters = NSCharacterSet.decimalDigits.inverted let intString = yourString.trimmingCharacters(in: notNumberCharacters)


Acepta solo el número de teléfono móvil

NSString * strippedNumber = [mobileNumber stringByReplacingOccurrencesOfString:@"[^0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [mobileNumber length])];


Aquí está la versión Swift de esto.

import UIKit import Foundation var phoneNumber = " 1 (888) 555-5551 " var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))


Aunque esta es una vieja pregunta con respuestas útiles, me perdí el soporte de formato internacional . Basado en la solución de simonobo, el juego de caracteres modificado incluye un signo más "+". Los números de teléfono internacionales también son compatibles con esta enmienda.

NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet: [[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"] invertedSet]] componentsJoinedByString:@""];

Las expresiones de Swift son

var phoneNumber = " +1 (234) 567-1000 " var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet() allowedCharactersSet.addCharactersInString("+") var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")

Que produce +12345671000 como formato de número de teléfono internacional común.


Basado en la respuesta de Jon Vogel aquí, es como una extensión de Swift String junto con algunas pruebas básicas.

import Foundation extension String { func stringByRemovingNonNumericCharacters() -> String { return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") } }

Y algunas pruebas que prueban al menos una funcionalidad básica:

import XCTest class StringExtensionTests: XCTestCase { func testStringByRemovingNonNumericCharacters() { let baseString = "123" var testString = baseString var newString = testString.stringByRemovingNonNumericCharacters() XCTAssertTrue(newString == testString) testString = "a123b" newString = testString.stringByRemovingNonNumericCharacters() XCTAssertTrue(newString == baseString) testString = "a=1-2_3@b" newString = testString.stringByRemovingNonNumericCharacters() XCTAssertTrue(newString == baseString) testString = "(999) 999-9999" newString = testString.stringByRemovingNonNumericCharacters() XCTAssertTrue(newString.characters.count == 10) XCTAssertTrue(newString == "9999999999") testString = "abc" newString = testString.stringByRemovingNonNumericCharacters() XCTAssertTrue(newString == "") } }

Esto responde a la pregunta del OP, pero podría modificarse fácilmente para dejarlo en caracteres relacionados con el número de teléfono, como ",; * # +"


Construyó la mejor solución como categoría para ayudar con problemas más amplios:

Interfaz:

@interface NSString (easyReplace) - (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set with:(NSString *)string; @end

Implementacion:

@implementation NSString (easyReplace) - (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set with:(NSString *)string { NSMutableString *strippedString = [NSMutableString stringWithCapacity:self.length]; NSScanner *scanner = [NSScanner scannerWithString:self]; while ([scanner isAtEnd] == NO) { NSString *buffer; if ([scanner scanCharactersFromSet:set intoString:&buffer]) { [strippedString appendString:buffer]; } else { [scanner setScanLocation:([scanner scanLocation] + 1)]; [strippedString appendString:string]; } } return [NSString stringWithString:strippedString]; } @end

Uso:

NSString *strippedString = [originalString stringByReplacingCharactersNotInSet: [NSCharacterSet setWithCharactersInString:@"01234567890" with:@""];


Creé una categoría en NSString para simplificar esta operación común.

NSString + AllowCharactersInSet.h

@interface NSString (AllowCharactersInSet) - (NSString *)stringByAllowingOnlyCharactersInSet:(NSCharacterSet *)characterSet; @end

NSString + AllowCharactersInSet.m

@implementation NSString (AllowCharactersInSet) - (NSString *)stringByAllowingOnlyCharactersInSet:(NSCharacterSet *)characterSet { NSMutableString *strippedString = [NSMutableString stringWithCapacity:self.length]; NSScanner *scanner = [NSScanner scannerWithString:self]; while (!scanner.isAtEnd) { NSString *buffer = nil; if ([scanner scanCharactersFromSet:characterSet intoString:&buffer]) { [strippedString appendString:buffer]; } else { scanner.scanLocation = scanner.scanLocation + 1; } } return strippedString; } @end


Creo que actualmente la mejor manera es:

phoneNumber.replacingOccurrences(of: "//D", with: "", options: String.CompareOptions.regularExpression)


Esto es genial, pero el código no funciona para mí en el iPhone 3.0 SDK.

Si defino strippedString como se muestra aquí, scanCharactersFromSet:intoString un BAD ACCESS error cuando intento imprimirlo después de la llamada a scanCharactersFromSet:intoString .

Si lo hago así:

NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];

Termino con una cadena vacía, pero el código no se cuelga.

Tuve que recurrir al buen viejo C en su lugar:

for (int i=0; i<[phoneNumber length]; i++) { if (isdigit([phoneNumber characterAtIndex:i])) { [strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]]; } }


Gracias por el ejemplo. Solo le falta una cosa al incremento de ScanLocation en caso de que uno de los caracteres en originalString no se encuentre dentro del objeto CharacterSet de números. He agregado una declaración else {} para solucionar esto.

NSString *originalString = @"(123) 123123 abc"; NSMutableString *strippedString = [NSMutableString stringWithCapacity:originalString.length]; NSScanner *scanner = [NSScanner scannerWithString:originalString]; NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"]; while ([scanner isAtEnd] == NO) { NSString *buffer; if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) { [strippedString appendString:buffer]; } // --------- Add the following to get out of endless loop else { [scanner setScanLocation:([scanner scanLocation] + 1)]; } // --------- End of addition } NSLog(@"%@", strippedString); // "123123123"


La respuesta aceptada es excesiva para lo que se está preguntando. Esto es mucho más simple:

NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];


No es necesario utilizar una biblioteca de expresiones regulares como sugieren las otras respuestas: la clase que buscas se llama NSScanner . Se usa de la siguiente manera:

NSString *originalString = @"(123) 123123 abc"; NSMutableString *strippedString = [NSMutableString stringWithCapacity:originalString.length]; NSScanner *scanner = [NSScanner scannerWithString:originalString]; NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"]; while ([scanner isAtEnd] == NO) { NSString *buffer; if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) { [strippedString appendString:buffer]; } else { [scanner setScanLocation:([scanner scanLocation] + 1)]; } } NSLog(@"%@", strippedString); // "123123123"

EDITAR: He actualizado el código porque el original fue escrito en la parte superior de mi cabeza y pensé que sería suficiente para apuntar a la gente en la dirección correcta. Parece que las personas buscan códigos que simplemente copian y pegan directamente en su aplicación.

También estoy de acuerdo en que la solución de Michael Pelz-Sherman es más adecuada que usar NSScanner , por lo que es posible que desee echar un vistazo a eso.


Para aquellos que buscan extracción de teléfono, puede extraer los números de teléfono de un texto usando NSDataDetector, por ejemplo:

NSString *userBody = @"This is a text with 30612312232 my phone"; if (userBody != nil) { NSError *error = NULL; NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:&error]; NSArray *matches = [detector matchesInString:userBody options:0 range:NSMakeRange(0, [userBody length])]; if (matches != nil) { for (NSTextCheckingResult *match in matches) { if ([match resultType] == NSTextCheckingTypePhoneNumber) { DbgLog(@"Found phone number %@", [match phoneNumber]); } } } }

`


Puede usar expresiones regulares en cadenas mutables:

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: @"[^//d]" options:0 error:nil]; [regex replaceMatchesInString:str options:0 range:NSMakeRange(0, str.length) withTemplate:@""];


Puede valer la pena señalar que la respuesta basada en los componentsSeparatedByCharactersInSet: aceptados componentsSeparatedByCharactersInSet: y componentsJoinedByString: no es una solución que ahorre memoria. Asigna memoria para el conjunto de caracteres, para una matriz y para una nueva cadena. Incluso si estas son solo asignaciones temporales, el procesamiento de muchas cadenas de esta manera puede llenar rápidamente la memoria.

Un enfoque más amigable con la memoria sería operar una copia mutable de la cadena en su lugar. En una categoría sobre NSString:

-(NSString *)stringWithNonDigitsRemoved { static NSCharacterSet *decimalDigits; if (!decimalDigits) { decimalDigits = [NSCharacterSet decimalDigitCharacterSet]; } NSMutableString *stringWithNonDigitsRemoved = [self mutableCopy]; for (CFIndex index = 0; index < stringWithNonDigitsRemoved.length; ++index) { unichar c = [stringWithNonDigitsRemoved characterAtIndex: index]; if (![decimalDigits characterIsMember: c]) { [stringWithNonDigitsRemoved deleteCharactersInRange: NSMakeRange(index, 1)]; index -= 1; } } return [stringWithNonDigitsRemoved copy]; }

Perfilar los dos enfoques ha demostrado esto usando alrededor de 2/3 menos de memoria.


Swift versión de la respuesta más popular:

var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))

Edición: sintaxis para Swift 2

let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")

Edición: sintaxis para Swift 3

let newString = oldString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")


Um. La primera respuesta me parece totalmente incorrecta. NSScanner está diseñado para analizar. A diferencia de Regex, te hace analizar la cadena un pequeño fragmento a la vez. Inicializarlo con una cadena, y mantiene un índice de qué tan lejos a lo largo de la cadena se obtiene; Ese índice es siempre su punto de referencia, y los comandos que le dé son relativos a ese punto. Usted le dice: "vale, dame el siguiente fragmento de caracteres en este conjunto" o "dame el número entero que encuentras en la cadena", y esos comienzan en el índice actual, y avanzan hasta que encuentran algo que no funciona partido. Si el primer carácter ya no coincide, el método devuelve NO y el índice no aumenta.

El código en el primer ejemplo está escaneando "(123) 456-7890" para caracteres decimales, que ya falla desde el primer carácter, por lo que la llamada a scanCharactersFromSet: intoString: deja el strippedString pasado solo y devuelve NO; El código ignora por completo el control del valor de retorno, dejando el StrippedString sin asignar. Incluso si el primer carácter fuera un dígito, ese código fallaría, ya que solo devolvería los dígitos que encuentre hasta el primer guión o paren o lo que sea.

Si realmente desea utilizar NSScanner, puede poner algo así en un bucle, y seguir buscando un valor de retorno NO, y si lo consigue, puede incrementar ScanLocation y escanear de nuevo; y también tiene que verificar isAEnd, y yada yada yada. En resumen, herramienta incorrecta para el trabajo. La solución de Michael es mejor.


Una vieja pregunta, pero ¿qué tal?

NSString *newString = [[origString componentsSeparatedByCharactersInSet: [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];

Explota la cadena fuente en el conjunto de los no dígitos, luego los vuelve a ensamblar utilizando un separador de cadenas vacío. No es tan eficiente como elegir caracteres, pero es mucho más compacto en el código.


Si solo buscas obtener los números de la cadena, ciertamente podrías usar expresiones regulares para analizarlos. Para hacer expresiones regulares en Objective-C, echa un vistazo a RegexKit . Editar: como señala @Nathan, usar NSScanner es una forma mucho más simple de analizar todos los números de una cadena. No estaba al tanto de esa opción, así que le aconsejé que lo sugiriera. (Ni siquiera me gusta utilizar Regex, por lo que prefiero los enfoques que no los requieren).

Si desea formatear números de teléfono para visualizar, vale la pena echarle un vistazo a NSNumberFormatter . Le sugiero que lea esta pregunta relacionada y este tutorial específico de iPhone para obtener consejos sobre cómo hacerlo. Recuerde que los números de teléfono tienen un formato diferente según la ubicación y / o ubicación.


NSString *originalPhoneNumber = @"(123) 123-456 abc"; NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]; NSString *trimmedPhoneNumber = [originalPhoneNumber stringByTrimmingCharactersInSet:numbers];

];

¡Mantenlo simple!