답변:
오래된 질문이지만 어떻습니까?
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
숫자가 아닌 세트에서 소스 문자열을 분해 한 다음 빈 문자열 구분 기호를 사용하여 소스 문자열을 다시 어셈블합니다. 문자를 선택하는 것만 큼 효율적이지는 않지만 코드가 훨씬 간결합니다.
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
작동하지 않는지 아십니까?
[NSCharacterSet decimalDigitCharacterSet]
는 숫자와 문자 만 포함 된 다른 것으로 바꿉니다 . 당신은을 만들어 하나를 구성 할 수 NSMutableCharaterSet
및 통과 decimalDigitCharacterSet
, uppercaseLetterCharacterSet
및 lowercaseLetterCharacterSet
에 formUnionWithCharacterSet:
. 주 letterCharacterSet
뿐만 아니라 마크를 포함하고, 저급와 대문자 버전 따라서 사용.
다른 답변에서 알 수 있듯이 정규 표현식 라이브러리를 사용할 필요가 없습니다 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의 솔루션이을 사용하는 것보다 더 적합하다는 점에 동의합니다 NSScanner
. 따라서 살펴보십시오.
허용되는 답변은 요청 된 내용에 대해 과잉입니다. 이것은 훨씬 간단합니다.
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
이것은 훌륭하지만 iPhone 3.0 SDK에서는 코드가 작동하지 않습니다.
여기에 표시된 것처럼 strippedString을 정의 BAD ACCESS error
하면 scanCharactersFromSet:intoString
호출 후 인쇄하려고 할 때가 나타납니다 .
내가 그렇게하면 :
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
빈 문자열로 끝나지 만 코드가 충돌하지 않습니다.
대신 좋은 오래된 C에 의지해야했습니다.
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
이것은 답변이있는 오래된 질문이지만 국제 형식 지원을 놓쳤습니다 . simonobo의 솔루션에 따라 변경된 문자 세트에는 더하기 부호 "+"가 포함됩니다. 국제 전화 번호도이 개정안에서 지원됩니다.
NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
invertedSet]]
componentsJoinedByString:@""];
스위프트 식은
var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")
일반적인 국제 전화 번호 형식으로 +12345671000이 표시됩니다.
여기 스위프트 버전이 있습니다.
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
가장 인기있는 답변의 신속한 버전 :
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: "")
예를 주셔서 감사합니다. originalString의 문자 중 하나를 숫자 CharacterSet 객체 내부에서 찾을 수없는 경우 scanLocation의 증분이 누락 된 것은 한 가지뿐입니다. 이 문제를 해결하기 위해 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"
그것은 허용 협조 할 수 있습니다 componentsSeparatedByCharactersInSet:
및 componentsJoinedByString:
기반 대답은 메모리 효율적인 솔루션이 아닙니다. 문자 집합, 배열 및 새 문자열에 대한 메모리를 할당합니다. 이것들이 임시 할당 일지라도 이런 식으로 많은 문자열을 처리하면 메모리를 빠르게 채울 수 있습니다.
보다 친근한 접근 방식은 문자열의 변경 가능한 복사본에서 작동하는 것입니다. 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 적은 메모리를 사용하여이를 알 수 있습니다.
광범위한 문제를 해결하기 위해 최고의 솔루션을 범주로 구축했습니다.
상호 작용:
@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:@""];
음 첫 번째 대답은 나에게 완전히 잘못된 것 같습니다. NSScanner는 실제로 구문 분석을위한 것입니다. 정규식과 달리 문자열을 한 번에 하나의 작은 덩어리로 구문 분석합니다. 문자열로 초기화하면 문자열을 따라 얼마나 멀리 떨어져 있는지에 대한 색인을 유지합니다. 해당 색인은 항상 참조 점이며, 제공 한 명령은 해당 지점과 관련이 있습니다. "이 세트에서 다음 문자 청크를주세요"또는 "문자열에서 찾은 정수를 줘"라고 말하면 현재 인덱스에서 시작하여 그렇지 않은 것을 찾을 때까지 앞으로 이동합니다. 시합. 맨 처음 문자가 이미 일치하지 않으면 메서드는 NO를 반환하고 인덱스는 증가하지 않습니다.
첫 번째 예제의 코드는 "(123) 456-7890"을 10 진수 문자로 스캔하고 있으며, 첫 번째 문자에서 이미 실패하므로 scanCharactersFromSet : intoString에 대한 호출은 전달 된 strippedString 만 남겨두고 NO를 반환합니다. 코드는 strippedString을 할당하지 않은 채로 반환 값 확인을 완전히 무시합니다. 첫 번째 문자가 숫자 인 경우에도 해당 코드는 첫 번째 대시 나 뾰족한 부분까지 찾을 수있는 숫자 만 반환하므로 실패합니다.
NSScanner를 실제로 사용하려면 루프에 이와 같은 것을 넣고 NO 반환 값을 계속 확인하고 스캔 위치를 늘리면 다시 스캔 위치를 지정할 수 있습니다. isAtEnd 및 yada yada yada도 확인해야합니다. 요컨대, 작업에 대한 잘못된 도구입니다. 마이클의 솔루션이 더 좋습니다.
전화 추출을 검색하는 경우 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에 범주를 만들었습니다.
@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
당신은 단지 문자열에서 숫자를 잡기 위해 찾고 있다면, 당신은 할 수 확실히 그들을 구문 분석하는 정규 표현식을 사용합니다. Objective-C에서 정규 표현식을 수행하려면 RegexKit을 확인하십시오 . 편집 : @Nathan이 지적했듯이 NSScanner를 사용하는 것이 문자열에서 모든 숫자를 구문 분석하는 훨씬 간단한 방법입니다. 나는 그 옵션을 완전히 알지 못했기 때문에 그 제안을 제안합니다. (나는 정규식을 직접 사용하는 것을 좋아하지 않으므로 필요하지 않은 접근법을 선호합니다.)
표시 할 전화 번호의 형식을 지정하려면 NSNumberFormatter를 살펴보십시오 . 이 관련 SO 질문 을 읽고 팁을 얻으십시오. 전화 번호는 위치 및 / 또는 지역에 따라 다르게 형식이 지정됩니다.
Jon Vogel의 답변을 바탕으로 몇 가지 기본 테스트와 함께 Swift String 확장입니다.
import Foundation
extension String {
func stringByRemovingNonNumericCharacters() -> String {
return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
}
}
그리고 몇 가지 테스트는 최소한 기본 기능을 입증합니다.
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];
];
간단하게 유지하십시오!
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]