J'ai un NSString (numéro de téléphone) avec des parenthèses et des traits d'union car certains numéros de téléphone sont formatés. Comment pourrais-je supprimer tous les caractères sauf les chiffres de la chaîne?
Vieille question, mais qu'en est-il:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
Il éclate la chaîne source sur l'ensemble des non-chiffres, puis les rassemble à l'aide d'un séparateur de chaîne vide. Pas aussi efficace que de cueillir des caractères, mais beaucoup plus compact dans le code.
Il n'est pas nécessaire d'utiliser une bibliothèque d'expressions régulières comme le suggèrent les autres réponses - la classe que vous suivez est appelée NSScanner
. Il est utilisé comme suit:
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"
EDIT: J'ai mis à jour le code parce que l'original a été écrit de mémoire et je me suis dit qu'il suffirait d'indiquer aux gens la bonne direction. Il semble que les gens recherchent du code qu'ils peuvent simplement copier-coller directement dans leur application.
Je conviens également que la solution de Michael Pelz-Sherman est plus appropriée que d'utiliser NSScanner
. Vous voudrez peut-être jeter un coup d'œil à cela.
La réponse acceptée est exagérée pour ce qui est demandé. C'est beaucoup plus simple:
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
C’est génial, mais le code ne fonctionne pas pour moi sur le SDK de l’iPhone 3.0.
Si je définis strippedString comme vous le montrez ici, je reçois un BAD ACCESS error
en essayant de l’imprimer après le scanCharactersFromSet:intoString
appel.
Si je le fais comme ça:
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
Je me retrouve avec une chaîne vide, mais le code ne plante pas.
J'ai dû recourir au bon vieux C à la place:
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
Bien que ce soit une vieille question avec des réponses de travail, j'ai manqué support de format international. Basé sur la solution de simonobo, le jeu de caractères modifié comprend un signe plus "+". Les numéros de téléphone internationaux sont également pris en charge par cet amendement.
NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
invertedSet]]
componentsJoinedByString:@""];
Les expressions Swift sont
var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")
Ce qui donne +12345671000 comme format de numéro de téléphone international commun.
Voici la version de Swift).
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Version rapide de la réponse la plus populaire:
var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Éditer: Syntaxe pour Swift 2
let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
Edit: Syntaxe for Swift 3
let newString = oldString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Merci pour l'exemple. Il ne manque qu’une chose qui manque l’incrément de scanLocation au cas où l’un des caractères de originalString ne se trouve pas dans l’objet numbers CharacterSet. J'ai ajouté une instruction else {} pour résoudre ce problème.
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"
Il accepte uniquement le numéro de mobile
NSString * strippedNumber = [mobileNumber stringByReplacingOccurrencesOfString:@"[^0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [mobileNumber length])];
Il convient de noter que la réponse acceptée basée sur componentsSeparatedByCharactersInSet:
Et componentsJoinedByString:
N'est pas une solution économe en mémoire. Il alloue de la mémoire pour le jeu de caractères, pour un tableau et pour une nouvelle chaîne. Même s'il ne s'agit que d'allocations temporaires, le traitement de nombreuses chaînes de cette manière peut rapidement remplir la mémoire.
Une approche plus conviviale en mémoire consisterait à utiliser une copie modifiable de la chaîne en place. Dans une catégorie sur 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];
}
Le profilage des deux approches a montré que cela nécessitait environ 2/3 de mémoire en moins.
Vous pouvez utiliser une expression régulière sur une chaîne mutable:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:
@"[^\\d]"
options:0
error:nil];
[regex replaceMatchesInString:str
options:0
range:NSMakeRange(0, str.length)
withTemplate:@""];
Construit la meilleure solution en tant que catégorie pour aider à résoudre des problèmes plus vastes:
Interface:
@interface NSString (easyReplace)
- (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set
with:(NSString *)string;
@end
Mise en oeuvre:
@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
Usage:
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)
Si vous cherchez seulement à saisir les nombres de la chaîne, vous pouvez utilisez certainement des expressions régulières pour les analyser. Pour faire des regex dans Objective-C, consultez RegexKit . Éditez: Comme le fait remarquer @Nathan, utiliser NSScanner est un moyen beaucoup plus simple d'analyser tous les nombres d'une chaîne. Je n’étais absolument pas au courant de cette option, aussi, aidez-le à le suggérer. (Je n'aime même pas utiliser regex moi-même, je préfère donc les approches qui n'en ont pas besoin.)
Si vous souhaitez formater les numéros de téléphone pour l'affichage, il convient de jeter un œil à NSNumberFormatter . Je vous suggère de lire ceci =SO question) pour obtenir des conseils à cet égard. N'oubliez pas que les numéros de téléphone sont formatés différemment selon l'emplacement et/ou les paramètres régionaux.
Pour ceux qui recherchent une extraction de téléphone, vous pouvez extraire les numéros de téléphone d'un texte à l'aide de NSDataDetector, par exemple:
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]);
}
}
}
}
`
Hum La première réponse me semble totalement fausse. NSScanner est vraiment destiné à l'analyse. Contrairement à regex, il vous permet d'analyser la chaîne un petit morceau à la fois. Vous l'initialisez avec une chaîne et il conserve un index indiquant le degré d'avancement de la chaîne; Cet index est toujours son point de référence et toutes les commandes que vous lui donnez sont relatives à ce point. Vous dites: "ok, donnez-moi le prochain bloc de caractères de cet ensemble" ou "donnez-moi le nombre entier que vous trouvez dans la chaîne", et ceux-ci commencent à l'index actuel et avancent jusqu'à ce qu'ils trouvent quelque chose qui ne fonctionne pas rencontre. Si le tout premier caractère ne correspond pas déjà, la méthode retourne NO et l'index ne s'incrémente pas.
Dans le premier exemple, le code recherche "(123) 456-7890" des caractères décimaux, qui échouent déjà à partir du tout premier caractère. L'appel de scanCharactersFromSet: intoString: laisse alors le strippedString transmis et renvoie NO; Le code ignore totalement la vérification de la valeur de retour, laissant le strippedString non affecté. Même si le premier caractère était un chiffre, ce code échouerait, car il ne renverrait que les chiffres trouvés jusqu'au premier tiret, paren ou autre.
Si vous voulez vraiment utiliser NSScanner, vous pouvez mettre quelque chose comme ça dans une boucle et continuer à rechercher une valeur de retour NO. Si vous obtenez cela, vous pouvez incrémenter scanLocation et numériser à nouveau. et vous devez également vérifier isAtEnd, et yada yada yada. En bref, mauvais outil pour le travail. La solution de Michael est meilleure.
J'ai créé une catégorie sur NSString pour simplifier cette opération courante.
@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
Swift 5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Je pense qu'actuellement, le meilleur moyen est:
phoneNumber.replacingOccurrences(of: "\\D",
with: "",
options: String.CompareOptions.regularExpression)