Ich habe einen NSString (Telefonnummer) mit einigen Klammern und Bindestrichen, da einige Telefonnummern formatiert sind. Wie würde ich alle Zeichen außer Zahlen aus der Zeichenfolge entfernen?
Ich habe einen NSString (Telefonnummer) mit einigen Klammern und Bindestrichen, da einige Telefonnummern formatiert sind. Wie würde ich alle Zeichen außer Zahlen aus der Zeichenfolge entfernen?
Antworten:
Alte Frage, aber wie wäre es mit:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
Es explodiert die Quellzeichenfolge in der Gruppe der nicht-stelligen Zeichen und setzt sie dann mithilfe eines leeren Zeichenfolgentrennzeichens wieder zusammen. Nicht so effizient wie das Durchsuchen von Zeichen, aber viel kompakter im Code.
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
nicht funktioniert?
[NSCharacterSet decimalDigitCharacterSet]
anderes ersetzen , das nur Zahlen und Buchstaben enthält. Sie können ein Konstrukt durch eine Erstellung NSMutableCharaterSet
und Weitergabe ein decimalDigitCharacterSet
, uppercaseLetterCharacterSet
und lowercaseLetterCharacterSet
zu formUnionWithCharacterSet:
. Beachten Sie, dass dies letterCharacterSet
auch Markierungen enthält, daher die Verwendung von Versionen in Klein- und Großbuchstaben.
Es ist nicht erforderlich, eine Bibliothek mit regulären Ausdrücken zu verwenden, wie aus den anderen Antworten hervorgeht - die Klasse, nach der Sie suchen, wird aufgerufen NSScanner
. Es wird wie folgt verwendet:
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"
BEARBEITEN: Ich habe den Code aktualisiert, weil das Original von oben auf meinen Kopf geschrieben wurde und ich dachte, es würde ausreichen, um die Leute in die richtige Richtung zu weisen. Es scheint, dass die Leute nach Code suchen, den sie einfach kopieren und direkt in ihre Anwendung einfügen können.
Ich stimme auch zu, dass die Lösung von Michael Pelz-Sherman besser geeignet ist als die Verwendung NSScanner
. Vielleicht möchten Sie sich das ansehen.
Die akzeptierte Antwort ist übertrieben für das, was gefragt wird. Das ist viel einfacher:
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
Das ist großartig, aber der Code funktioniert bei mir auf dem iPhone 3.0 SDK nicht.
Wenn ich strippedString so definiere, wie Sie es hier zeigen, erhalte ich eine BAD ACCESS error
beim Versuch, es nach dem scanCharactersFromSet:intoString
Aufruf zu drucken angezeigt.
Wenn ich es so mache:
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
Am Ende habe ich eine leere Zeichenfolge, aber der Code stürzt nicht ab.
Ich musste stattdessen auf das gute alte C zurückgreifen:
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
Obwohl dies eine alte Frage mit funktionierenden Antworten ist, habe ich die Unterstützung für internationale Formate verpasst . Basierend auf der Lösung von Simonobo enthält der geänderte Zeichensatz ein Pluszeichen "+". Auch internationale Telefonnummern werden von dieser Änderung unterstützt.
NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
invertedSet]]
componentsJoinedByString:@""];
Die Swift-Ausdrücke sind
var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")
Dies ergibt +12345671000 als allgemeines internationales Telefonnummernformat.
Hier ist die Swift-Version davon.
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Schnelle Version der beliebtesten Antwort:
var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Edit: Syntax für Swift 2
let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
Edit: Syntax für Swift 3
let newString = oldString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Danke für das Beispiel. Es fehlt nur eines, das Inkrement der scanLocation, falls eines der Zeichen in originalString nicht im Zeichen CharacterSet-Objekt gefunden wird. Ich habe eine else {} -Anweisung hinzugefügt, um dies zu beheben.
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"
Es kann erwähnenswert sein, dass die akzeptierte componentsSeparatedByCharactersInSet:
und componentsJoinedByString:
basierte Antwort keine speichereffiziente Lösung ist. Es reserviert Speicher für den Zeichensatz, für ein Array und für eine neue Zeichenfolge. Selbst wenn es sich nur um temporäre Zuweisungen handelt, kann die Verarbeitung vieler Zeichenfolgen auf diese Weise den Speicher schnell füllen.
Ein speicherfreundlicherer Ansatz wäre, eine veränderbare Kopie der vorhandenen Zeichenfolge zu bearbeiten. In einer Kategorie über 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];
}
Die Profilerstellung der beiden Ansätze hat gezeigt, dass etwa 2/3 weniger Speicher benötigt wird.
Entwickelte die Top-Lösung als Kategorie, um bei umfassenderen Problemen zu helfen:
Schnittstelle:
@interface NSString (easyReplace)
- (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set
with:(NSString *)string;
@end
Implementierung:
@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
Verwendung:
NSString *strippedString =
[originalString stringByReplacingCharactersNotInSet:
[NSCharacterSet setWithCharactersInString:@"01234567890"
with:@""];
schnell 4.1
var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)
Äh. Die erste Antwort scheint mir völlig falsch. NSScanner ist wirklich zum Parsen gedacht. Im Gegensatz zu Regex müssen Sie die Zeichenfolge jeweils um einen winzigen Block analysieren. Sie initialisieren es mit einer Zeichenfolge und es wird ein Index darüber beibehalten, wie weit es entlang der Zeichenfolge gekommen ist. Dieser Index ist immer sein Referenzpunkt, und alle Befehle, die Sie ihm geben, beziehen sich auf diesen Punkt. Sie sagen: "Okay, geben Sie mir den nächsten Teil der Zeichen in diesem Satz" oder "Geben Sie mir die Ganzzahl, die Sie in der Zeichenfolge finden". Diese beginnen am aktuellen Index und bewegen sich vorwärts, bis sie etwas finden, das dies nicht tut Spiel. Wenn das allererste Zeichen bereits nicht übereinstimmt, gibt die Methode NO zurück und der Index wird nicht erhöht.
Der Code im ersten Beispiel durchsucht "(123) 456-7890" nach Dezimalzeichen, was bereits ab dem ersten Zeichen fehlschlägt. Daher ruft der Aufruf von scanCharactersFromSet: intoString: den übergebenen strippedString in Ruhe und gibt NO zurück. Der Code ignoriert die Überprüfung des Rückgabewerts vollständig und lässt den strippedString nicht zugewiesen. Selbst wenn das erste Zeichen eine Ziffer wäre, würde dieser Code fehlschlagen, da er nur die Ziffern zurückgibt, die er bis zum ersten Strich oder Paren oder was auch immer findet.
Wenn Sie NSScanner wirklich verwenden möchten, können Sie so etwas in eine Schleife einfügen und weiter nach einem NO-Rückgabewert suchen. Wenn Sie dies erhalten, können Sie den scanLocation erhöhen und erneut scannen. und Sie müssen auch isAtEnd und yada yada yada überprüfen. Kurz gesagt, falsches Werkzeug für den Job. Michaels Lösung ist besser.
Für diejenigen, die nach Telefonextraktion suchen, können Sie die Telefonnummern mit NSDataDetector aus einem Text extrahieren, zum Beispiel:
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]);
}
}
}
}
`
Ich habe eine Kategorie in NSString erstellt, um diesen allgemeinen Vorgang zu vereinfachen.
@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
Wenn Sie nur versuchen, die Zahlen aus der Zeichenfolge zu entnehmen , können Sie sie auch mit regulären Ausdrücken analysieren. Informationen zum Ausführen von Regex in Objective-C finden Sie in RegexKit . Bearbeiten: Wie @Nathan hervorhebt, ist die Verwendung von NSScanner eine viel einfachere Möglichkeit, alle Zahlen aus einer Zeichenfolge zu analysieren. Ich war mir dieser Option überhaupt nicht bewusst, also bitte ich ihn, sie vorzuschlagen. (Ich mag es nicht einmal, Regex selbst zu verwenden, deshalb bevorzuge ich Ansätze, die sie nicht erfordern.)
Wenn Sie Telefonnummern für die Anzeige formatieren möchten, sollten Sie sich NSNumberFormatter ansehen . Ich schlage vor, dass Sie diese verwandte SO-Frage lesen , um Tipps dazu zu erhalten. Denken Sie daran, dass Telefonnummern je nach Standort und / oder Gebietsschema unterschiedlich formatiert sind.
Swift 5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Basierend auf Jon Vogels Antwort hier handelt es sich um eine Swift String-Erweiterung zusammen mit einigen grundlegenden Tests.
import Foundation
extension String {
func stringByRemovingNonNumericCharacters() -> String {
return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
}
}
Und einige Tests, die zumindest grundlegende Funktionen belegen:
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 == "")
}
}
Dies beantwortet die Frage des OP, kann jedoch leicht geändert werden, um telefonnummernbezogene Zeichen wie ",; * # +" zu belassen.
NSString *originalPhoneNumber = @"(123) 123-456 abc";
NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
NSString *trimmedPhoneNumber = [originalPhoneNumber stringByTrimmingCharactersInSet:numbers];
];
Halte es einfach!
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]