从NSString删除所有数字

我有一个NSString(电话号码)与一些括号和连字符作为一些电话号码格式。 我将如何删除string中除数字之外的所有字符?

老问题,但如何:

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

它分解非数字集合中的源string,然后使用空string分隔符重新组合它们。 效率不如挑选字符,但代码更紧凑。

正如其他答案所build议的,不需要使用正则expression式库 – 您所追求的类称为NSScanner 。 它的用法如下:

 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" 

编辑:我已经更新了代码,因为原来是写在我的头顶,我认为这将足以指出人们在正确的方向。 看起来,人们在编写代码之后,可以直接复制粘贴到应用程序中。

我也同意Michael Pelz-Sherman的解决scheme比使用NSScanner更合适,所以你可能想看看这个。

被接受的答案对于被问到的东西是过分的。 这很简单:

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

这太棒了,但是代码在iPhone 3.0 SDK上不适用于我。

如果我在这里显示的定义了strippedString,那么在scanCharactersFromSet:intoString调用之后尝试打印时会出现BAD ACCESS error

如果我这样做:

 NSMutableString *strippedString = [NSMutableString stringWithCapacity:10]; 

我结束了一个空string,但代码不会崩溃。

我不得不求助于老的C:

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

虽然这是一个有工作答案的老问题,但我错过了国际格式的支持 。 基于simonobo的解决scheme,改变的字符集包括一个加号“+”。 国际电话号码也受到该修正案的支持。

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

Swiftexpression式是

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

作为常用的国际电话号码格式,产生+12345671000。

这是这个Swift版本。

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

Swift版最受欢迎的答案是:

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

编辑:语法为Swift 2

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

编辑:语法为Swift 3

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

感谢这个例子。 只有一件东西遗漏了scanLocation的增量,以防在originalString中的一个字符在数字CharacterSet对象内找不到。 我已经添加了一个else {}语句来解决这个问题。

 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" 

它只接受手机号码

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

可能值得注意的是,接受的componentsSeparatedByCharactersInSet: SegmentByCharactersInSet componentsSeparatedByCharactersInSet:componentsJoinedByString:基于的答案不是一个内存有效的解决scheme。 它为字符集,数组和新string分配内存。 即使这些只是暂时的分配,以这种方式处理大量的string可以快速填充内存。

一个内存友好的方法是在string的可变副本上进行操作。 在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]; } 

分析这两种方法已经表明这使用了大约2/3的内存。

你可以在可变string上使用正则expression式:

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

Swift 3

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

将顶级解决scheme作为一个类别来帮助解决更广泛的问题:

接口:

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

实行:

 @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 

用法:

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

如果你只是想从string中获取数字,你当然可以使用正则expression式来parsing它们。 在Objective-C中做正则expression式,看看RegexKit 。 编辑: 正如@Nathan指出,使用NSScanner是一个更简单的方法来parsingstring中的所有数字。 我完全不知道这个select,所以支持他提出这个build议。 (我甚至不喜欢自己使用正则expression式,所以我更喜欢不需要它们的方法。)

如果你想格式化电话号码显示,值得看看NSNumberFormatter 。 我build议你通读这个相关的SO问题和这个iPhone特定的教程,以获得有关这样做的提示。 请记住,根据位置和/或语言环境,电话号码的格式不同。

嗯。 第一个答案似乎完全错了。 NSScanner是真正意义上的parsing。 与正则expression式不同的是,它一次只能parsing一个小块。 你用一个string对它进行初始化,并且维护一个它得到的string有多远的索引。 这个索引始终是它的参考点,你给它的任何命令都是相对于这个点的。 你告诉它,“好的,给我这个集合中的下一个字符块”或者“给我你在string中find的整数”,然后从当前索引开始,向前移动,直到find不是比赛。 如果第一个字符已经不匹配,那么方法返回NO,并且索引不增加。

在第一个例子中的代码是扫描“(123)456-7890”十进制字符,它已经失败的第一个字符,所以调用scanCharactersFromSet:intoString:离开传入的strippedString单独,并返回NO; 该代码完全忽略检查返回值,留下strippedString未分配。 即使第一个字符是数字,那么这个代码也会失败,因为它只会返回find的数字,直到第一个短划线或字母或其他。

如果你真的想使用NSScanner,你可以把这样的东西放在一个循环中,并检查一个NO返回值,如果你得到这个,你可以增加scanLocation并重新扫描; 你也必须检查isAtEnd和yada yada yada。 总之,这个工作的错误工具。 迈克尔的解决scheme更好。

对于那些search手机提取,您可以使用NSDataDetector从文本中提取电话号码,例如:

 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]); } } } } 

`

我在NSString上创build了一个类来简化这个常见的操作。

的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 

我认为目前最好的方法是:

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

根据Jon Vogel的答案,这是一个Swiftstring扩展以及一些基本的testing。

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

而一些testing至lesscertificate了基本function:

 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 == "") } } 

这回答OP的问题,但它可以很容易地修改,以留下电话号码相关的字符,如“,; *#+”

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

]。

把事情简单化!