Ho un NSString (numero di telefono) con alcune parentesi e trattini poiché alcuni numeri di telefono sono formattati. Come rimuoverei tutti i caratteri tranne i numeri dalla stringa?
Ho un NSString (numero di telefono) con alcune parentesi e trattini poiché alcuni numeri di telefono sono formattati. Come rimuoverei tutti i caratteri tranne i numeri dalla stringa?
Risposte:
Vecchia domanda, ma che ne dici di:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
Esplode la stringa di origine sull'insieme di non cifre, quindi le riassembla usando un separatore di stringhe vuoto. Non efficiente quanto la selezione dei caratteri, ma molto più compatto nel codice.
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
non funziona?
[NSCharacterSet decimalDigitCharacterSet]
con un altro che contiene solo numeri e lettere. È possibile costruire una per la creazione di un NSMutableCharaterSet
e passando una decimalDigitCharacterSet
, uppercaseLetterCharacterSet
e lowercaseLetterCharacterSet
al formUnionWithCharacterSet:
. Si noti che letterCharacterSet
include anche i segni, quindi l'uso di versioni minuscole e maiuscole.
Non è necessario utilizzare una libreria di espressioni regolari come suggeriscono le altre risposte: viene chiamata la classe che stai cercando NSScanner
. È usato come segue:
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: ho aggiornato il codice perché l'originale è stato cancellato dalla parte superiore della mia testa e ho pensato che sarebbe stato sufficiente per indirizzare le persone nella giusta direzione. Sembra che le persone siano alla ricerca di codice che possano semplicemente copiare e incollare direttamente nella loro applicazione.
Sono anche d'accordo sul fatto che la soluzione di Michael Pelz-Sherman sia più appropriata dell'uso NSScanner
, quindi potresti voler dare un'occhiata a quello.
La risposta accettata è eccessiva per ciò che viene chiesto. Questo è molto più semplice:
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
Questo è fantastico, ma il codice non funziona per me sull'SDK di iPhone 3.0.
Se definisco strippedString come mostrato qui, ottengo un BAD ACCESS error
segno quando provo a stamparlo dopo la scanCharactersFromSet:intoString
chiamata.
Se lo faccio così:
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
Finisco con una stringa vuota, ma il codice non va in crash.
Invece ho dovuto ricorrere alla buona vecchia C:
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
Sebbene questa sia una vecchia domanda con risposte funzionanti, mi mancava il supporto per i formati internazionali . Basato sulla soluzione di simonobo, il set di caratteri modificato include un segno più "+". Anche i numeri di telefono internazionali sono supportati da questo emendamento.
NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
invertedSet]]
componentsJoinedByString:@""];
Le espressioni Swift sono
var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")
Che produce +12345671000 come un formato di numero di telefono internazionale comune.
Ecco la versione Swift di questo.
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Versione rapida della risposta più popolare:
var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Modifica: sintassi per Swift 2
let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
Modifica: sintassi per Swift 3
let newString = oldString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Grazie per l'esempio Manca solo una cosa per l'incremento di scanLocation nel caso in cui uno dei caratteri in originalString non venga trovato all'interno dell'oggetto CharacterSet numeri. Ho aggiunto un'altra dichiarazione {} per risolvere questo problema.
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"
Potrebbe valere la pena notare che l'accettato componentsSeparatedByCharactersInSet:
ecomponentsJoinedByString:
risposta basata non è una soluzione efficiente in termini di memoria. Alloca memoria per il set di caratteri, per un array e per una nuova stringa. Anche se si tratta solo di allocazioni temporanee, l'elaborazione di molte stringhe in questo modo può riempire rapidamente la memoria.
Un approccio più amichevole della memoria sarebbe quello di operare su una copia mutabile della stringa in atto. In una categoria su 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];
}
La profilazione dei due approcci lo ha dimostrato usando circa 2/3 di memoria in meno.
Creata la migliore soluzione come categoria per aiutare con problemi più ampi:
Interfaccia:
@interface NSString (easyReplace)
- (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set
with:(NSString *)string;
@end
Implemenation:
@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:@""];
rapido 4.1
var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)
Um. La prima risposta mi sembra totalmente sbagliata. NSScanner è davvero pensato per l'analisi. A differenza di regex, ti fa analizzare la stringa un piccolo pezzo alla volta. Lo inizializzi con una stringa e mantiene un indice di quanto è lungo la stringa; Quell'indice è sempre il suo punto di riferimento e tutti i comandi che gli dai sono relativi a quel punto. Dici "ok, dammi il prossimo pezzo di caratteri in questo set" o "dammi il numero intero che trovi nella stringa", e quelli iniziano con l'indice corrente e vanno avanti finché non trovano qualcosa che non incontro. Se il primissimo carattere non corrisponde già, il metodo restituisce NO e l'indice non aumenta.
Il codice nel primo esempio è la scansione di "(123) 456-7890" alla ricerca di caratteri decimali, che non riescono già dal primo carattere, quindi la chiamata a scanCharactersFromSet: intoString: lascia da solo lo strippedString passato e restituisce NO; Il codice ignora totalmente il controllo del valore restituito, lasciando strippedString non assegnato. Anche se il primo carattere fosse una cifra, quel codice fallirebbe, poiché restituirebbe solo le cifre che trova fino al primo trattino o parentesi o altro.
Se davvero volessi usare NSScanner, potresti mettere qualcosa del genere in un ciclo e continuare a cercare un valore di ritorno NO, e se lo ottieni puoi incrementare scanLocation ed eseguire nuovamente la scansione; e devi anche controllare isAtEnd e yada yada yada. In breve, strumento sbagliato per il lavoro. La soluzione di Michael è migliore.
Per coloro che cercano l'estrazione del telefono, è possibile estrarre i numeri di telefono da un testo utilizzando NSDataDetector, ad esempio:
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]);
}
}
}
}
`
Ho creato una categoria su NSString per semplificare questa operazione comune.
@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 stai solo cercando di afferrare i numeri dalla stringa, si potrebbe certamente utilizzare le espressioni regolari per analizzare fuori. Per eseguire regex in Objective-C, controlla RegexKit . Modifica: Come sottolinea @Nathan, l'uso di NSScanner è un modo molto più semplice per analizzare tutti i numeri da una stringa. Non ero assolutamente a conoscenza di quell'opzione, quindi sono propenso a lui per averlo suggerito. (Non mi piace nemmeno usare regex da solo, quindi preferisco approcci che non li richiedono.)
Se vuoi formattare i numeri di telefono per la visualizzazione, vale la pena dare un'occhiata a NSNumberFormatter . Ti suggerisco di leggere questa domanda SO relativa per suggerimenti su come farlo. Ricorda che i numeri di telefono sono formattati in modo diverso a seconda della posizione e / o delle impostazioni internazionali.
Swift 5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Basato sulla risposta di Jon Vogel qui è come estensione Swift String insieme ad alcuni test di base.
import Foundation
extension String {
func stringByRemovingNonNumericCharacters() -> String {
return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
}
}
E alcuni test che dimostrano almeno la funzionalità di base:
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 == "")
}
}
Questo risponde alla domanda del PO ma potrebbe essere facilmente modificato per lasciare nei caratteri relativi al numero di telefono come ",; * # +"
NSString *originalPhoneNumber = @"(123) 123-456 abc";
NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
NSString *trimmedPhoneNumber = [originalPhoneNumber stringByTrimmingCharactersInSet:numbers];
];
Mantienilo semplice!
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]