Eu tenho um NSString (número de telefone) com alguns parênteses e hífens, pois alguns números de telefone são formatados. Como removeria todos os caracteres, exceto números, da string?
Eu tenho um NSString (número de telefone) com alguns parênteses e hífens, pois alguns números de telefone são formatados. Como removeria todos os caracteres, exceto números, da string?
Respostas:
Pergunta antiga, mas que tal:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
Explode a string de origem no conjunto de não-dígitos e, em seguida, remonta-os usando um separador de string vazio. Não é tão eficiente quanto escolher caracteres, mas é muito mais compacto no código.
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
não está funcionando?
[NSCharacterSet decimalDigitCharacterSet]
por outro que contenha apenas números e letras. Você pode construir um, criando um NSMutableCharaterSet
e passar um decimalDigitCharacterSet
, uppercaseLetterCharacterSet
e lowercaseLetterCharacterSet
para formUnionWithCharacterSet:
. Observe que também letterCharacterSet
inclui marcas, portanto, o uso de versões em maiúsculas e minúsculas.
Não é necessário usar uma biblioteca de expressões regulares, como as outras respostas sugerem - a classe que você procura é chamada NSScanner
. É usado da seguinte maneira:
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: Eu atualizei o código porque o original foi escrito em cima da minha cabeça e achei que seria suficiente apontar as pessoas na direção certa. Parece que as pessoas estão atrás do código e podem simplesmente copiar e colar diretamente no aplicativo.
Também concordo que a solução de Michael Pelz-Sherman é mais apropriada do que usar NSScanner
, portanto, você pode dar uma olhada nisso.
A resposta aceita é um exagero para o que está sendo perguntado. Isso é muito mais simples:
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
Isso é ótimo, mas o código não funciona para mim no iPhone 3.0 SDK.
Se eu definir strippedString como você mostra aqui, recebo um BAD ACCESS error
ao tentar imprimi-lo após a scanCharactersFromSet:intoString
chamada.
Se eu fizer assim:
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
Acabo com uma string vazia, mas o código não falha.
Eu tive que recorrer ao bom e velho C:
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
Embora essa seja uma pergunta antiga com respostas funcionais, perdi o suporte ao formato internacional . Com base na solução de simonobo, o conjunto de caracteres alterado inclui um sinal de mais "+". Os números de telefone internacionais também são suportados por esta alteração.
NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
invertedSet]]
componentsJoinedByString:@""];
As expressões Swift são
var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")
Que gera +12345671000 como um formato de número de telefone internacional comum.
Aqui está a versão Swift disso.
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Versão rápida da resposta mais popular:
var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Edit: Sintaxe para Swift 2
let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
Edit: Sintaxe para Swift 3
let newString = oldString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Obrigado pelo exemplo. Falta apenas uma coisa para o incremento do scanLocation, caso um dos caracteres em originalString não seja encontrado dentro do objeto CharacterSet de números. Eu adicionei uma instrução else {} para corrigir isso.
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"
Pode valer a pena notar que a resposta aceita componentsSeparatedByCharactersInSet:
e componentsJoinedByString:
baseada não é uma solução eficiente em memória. Aloca memória para o conjunto de caracteres, para uma matriz e para uma nova sequência. Mesmo que sejam apenas alocações temporárias, o processamento de muitas seqüências dessa maneira pode preencher rapidamente a memória.
Uma abordagem mais amigável à memória seria operar uma cópia mutável da string em vigor. Em uma categoria 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];
}
A criação de perfil das duas abordagens mostrou isso usando cerca de 2/3 a menos de memória.
Construiu a solução principal como uma categoria para ajudar com problemas mais amplos:
Interface:
@interface NSString (easyReplace)
- (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set
with:(NSString *)string;
@end
Implementação:
@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:@""];
let notNumberCharacters = NSCharacterSet.decimalDigits.inverted
let intString = yourString.trimmingCharacters(in: notNumberCharacters)
swift 4.1
var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)
Hum. A primeira resposta parece totalmente errada para mim. O NSScanner é realmente destinado à análise. Ao contrário do regex, ele faz com que você analise a string, um pedaço minúsculo de cada vez. Você o inicializa com uma sequência e mantém um índice de quanto tempo ela foi obtida; Esse índice é sempre o seu ponto de referência, e quaisquer comandos que você der são relativos a esse ponto. Você diz: "ok, me dê o próximo pedaço de caracteres deste conjunto" ou "me dê o número inteiro encontrado na string", e eles começam no índice atual e avançam até encontrar algo que não Combine. Se o primeiro caractere já não corresponder, o método retornará NO e o índice não será incrementado.
O código no primeiro exemplo está varrendo "(123) 456-7890" quanto a caracteres decimais, que já falham desde o primeiro caractere; portanto, a chamada para scanCharactersFromSet: intoString: deixa o strippedString transmitido sozinho e retorna NO; O código ignora totalmente a verificação do valor de retorno, deixando a strippedString não atribuída. Mesmo se o primeiro caractere fosse um dígito, esse código falharia, pois retornaria apenas os dígitos encontrados até o primeiro traço ou parêntese ou o que quer.
Se você realmente quisesse usar o NSScanner, poderia colocar algo assim em um loop e continuar verificando o valor de retorno NO; se conseguir, poderá incrementar o scanLocation e verificar novamente; e você também precisa verificar isAtEnd e yada yada yada. Em suma, ferramenta errada para o trabalho. A solução de Michael é melhor.
Para quem procura extração de telefone, é possível extrair os números de telefone de um texto usando o NSDataDetector, por exemplo:
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]);
}
}
}
}
`
Eu criei uma categoria no NSString para simplificar essa operação comum.
@interface NSString (AllowCharactersInSet)
- (NSString *)stringByAllowingOnlyCharactersInSet:(NSCharacterSet *)characterSet;
@end
@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
Se você deseja apenas pegar os números da sequência, certamente pode usar expressões regulares para analisá-los. Para fazer regex no Objective-C, confira RegexKit . Editar: Como o @Nathan aponta, usar o NSScanner é uma maneira muito mais simples de analisar todos os números de uma string. Eu não estava totalmente ciente dessa opção, então adereços para ele por sugeri-la. (Eu nem gosto de usar regex, então prefiro abordagens que não as exijam.)
Se você deseja formatar números de telefone para exibição, vale a pena dar uma olhada no NSNumberFormatter . Sugiro que você leia esta pergunta relacionada ao SO para obter dicas sobre como fazê-lo. Lembre-se de que os números de telefone são formatados de maneira diferente, dependendo do local e / ou local.
Swift 5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Com base na resposta de Jon Vogel, aqui é como uma extensão Swift String, juntamente com alguns testes básicos.
import Foundation
extension String {
func stringByRemovingNonNumericCharacters() -> String {
return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
}
}
E alguns testes comprovando pelo menos a funcionalidade 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 == "")
}
}
Isso responde à pergunta do OP, mas poderia ser facilmente modificado para deixar caracteres relacionados ao número de telefone como ",; * # +"
NSString *originalPhoneNumber = @"(123) 123-456 abc";
NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
NSString *trimmedPhoneNumber = [originalPhoneNumber stringByTrimmingCharactersInSet:numbers];
];
Mantenha simples!
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]