NSString에서 숫자를 제외한 모든 숫자 제거


157

일부 전화 번호가 형식화되어 있으므로 일부 괄호와 하이픈이있는 NSString (전화 번호)이 있습니다. 문자열에서 숫자를 제외한 모든 문자를 어떻게 제거합니까?

답변:


375

오래된 질문이지만 어떻습니까?

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

숫자가 아닌 세트에서 소스 문자열을 분해 한 다음 빈 문자열 구분 기호를 사용하여 소스 문자열을 다시 어셈블합니다. 문자를 선택하는 것만 큼 효율적이지는 않지만 코드가 훨씬 간결합니다.


6
감사! 다른 초보자의 경우 다음을 수행하여 사용자 정의 NSCharacterSet을 만들 수 있습니다.NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]
guptron

1
큰 감사합니다! 내 호기심을 위해서 왜 NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]작동하지 않는지 아십니까?
토마스 베스 네 하드

1
@Tommecpe stringByTrimmingCharactersInSet은 문자열의 시작과 끝에서만 제거하므로 일치하지 않는 첫 번째 문자 이후 또는 마지막 일치하지 않는 문자 이전에는 영향을 미치지 않습니다.
simonobo 2016 년

숫자와 알파벳 만 유지하고 싶습니다. 어떻게해야합니까?
재키

1
위의 예에서 @Jacky [NSCharacterSet decimalDigitCharacterSet]는 숫자와 문자 만 포함 된 다른 것으로 바꿉니다 . 당신은을 만들어 하나를 구성 할 수 NSMutableCharaterSet및 통과 decimalDigitCharacterSet, uppercaseLetterCharacterSetlowercaseLetterCharacterSetformUnionWithCharacterSet:. 주 letterCharacterSet뿐만 아니라 마크를 포함하고, 저급와 대문자 버전 따라서 사용.
카담

75

다른 답변에서 알 수 있듯이 정규 표현식 라이브러리를 사용할 필요가 없습니다 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. 따라서 살펴보십시오.


+1 문제를 직접 해결하는 좋은 답변. 나는이 접근법을 옹호하기 위해 내 대답을 편집했지만, 여전히 도움이되기 때문에 후반부를 그대로 남겨두고 있습니다. (다음으로 독자들에게만 공개한다면, 하향 투표 할 때 건설적인 의견을 남길 수 있습니까?)
Quinn Taylor

4
NSCharacterSet의 + decimalDigitCharacterSet 메소드가 모든 10 진수를 제공한다는 것을 아는 것이 편리 할 수 ​​있습니다. 아랍어-숫자 숫자 (١٢٣٤٥ 등)를 포함하여 10 진수를 나타내는 모든 기호가 포함되어 있기 때문에 이는 Nathan 집합 세트와 약간 다릅니다. 응용 프로그램에 따라 때로는 문제가 될 수 있지만 일반적으로 양호하거나 중립적이며 입력하기에는 약간 짧습니다.
Rob Napier

이 답변이 실제로 작동하지 않으며 문제에 대한 올바른 접근 방법이 아니라고 확신합니다. 그림과 같이 실제로 코드를 시도하면 (먼저 NSLog에 첫 번째 매개 변수 앞에 @를 추가하여 objc 문자열로 만드는) <null>을 인쇄하거나 충돌하는 것을 알 수 있습니다. 왜? 아래 답변을 참조하십시오.
Jack Nutting

다른 답변이 필요하지 않습니다. 이것이 바로 의견입니다. Michael Pelz-Sherman의 솔루션에 대한 참조를 포함하여 솔루션을 업데이트했습니다.
Nathan de Vries

4
복잡합니다.
ryyst

63

허용되는 답변은 요청 된 내용에 대해 과잉입니다. 이것은 훨씬 간단합니다.

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

2
(현재) 승인 된 답변은이 답변과 거의 동일하지만 13 개월 전에 게시되었습니다.
Caleb

내가 이것에 대답했을 때, 그것은 대답이 없었습니다. 보인다 있지만 현재의 대답은 이미 제안하고 나는 그것을 놓친했다 : web.archive.org/web/20101115214033/http://stackoverflow.com/...
야신 Filali

30

이것은 훌륭하지만 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]];
    }
}

3.0을 실행 중이며 이것이 효과적입니다. Vries의 더 인기있는 답변은 효과가 없었습니다.
Neo42

최고의 답변은 저에게 효과적이지 않습니다. 스캐너가 ()에 도달하면 정지합니다-또는이 답변은 훌륭합니다! 좋은 오래된 C !! 감사합니다
Jeff

2
전화 번호에는 '+'문자를 사용할 수 있어야합니다.
Prcela

27

이것은 답변이있는 오래된 질문이지만 국제 형식 지원을 놓쳤습니다 . 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이 표시됩니다.


2
특히 국제 전화 번호에 더하기 기호가 필요한 경우 목록에서 가장 좋은 솔루션입니다.
UXUiOS

어떤 이유로, 거꾸로 된 문자 집합을 사용하면 성능이 나빠질 때 나를 두려워합니다. 이것이 근거없는 두려움인지 아는 사람이 있습니까?
devios1

이것은 효과가 있었다! 작동 방식을 설명해 주시겠습니까? @ 알렉스
Jayprakash Dubey

11

여기 스위프트 버전이 있습니다.

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

스위프트 2.0 : phoneNumber.componentsSeparatedByCharactersInSet (NSCharacterSet.decimalDigitCharacterSet (). invertedSet) .joinWithSeparator ( "")
iluvatar_GR

11

가장 인기있는 답변의 신속한 버전 :

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: "")

소수 구분 기호를 유지하는 방법이 있습니까? 장치의 기본 설정에 따른 점 (또는 쉼표)? 솔루션은 숫자를 제외한 모든 것을 제거합니다
Nicholas

5

예를 주셔서 감사합니다. 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"

4

휴대 전화 번호 만 허용

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

3

그것은 허용 협조 할 수 있습니다 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 적은 메모리를 사용하여이를 알 수 있습니다.


2

가변 문자열에 정규식을 사용할 수 있습니다.

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:
                                @"[^\\d]"
                                options:0
                                error:nil];

[regex replaceMatchesInString:str
                      options:0 
                        range:NSMakeRange(0, str.length) 
                 withTemplate:@""];

1

광범위한 문제를 해결하기 위해 최고의 솔루션을 범주로 구축했습니다.

상호 작용:

@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:@""];

1

스위프트 3

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

시작과 끝에서 숫자가 아닌 문자 만 자릅니다.
Shebuka

1

스위프트 4.1

var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)

0

음 첫 번째 대답은 나에게 완전히 잘못된 것 같습니다. NSScanner는 실제로 구문 분석을위한 것입니다. 정규식과 달리 문자열을 한 번에 하나의 작은 덩어리로 구문 분석합니다. 문자열로 초기화하면 문자열을 따라 얼마나 멀리 떨어져 있는지에 대한 색인을 유지합니다. 해당 색인은 항상 참조 점이며, 제공 한 명령은 해당 지점과 관련이 있습니다. "이 세트에서 다음 문자 청크를주세요"또는 "문자열에서 찾은 정수를 줘"라고 말하면 현재 인덱스에서 시작하여 그렇지 않은 것을 찾을 때까지 앞으로 이동합니다. 시합. 맨 처음 문자가 이미 일치하지 않으면 메서드는 NO를 반환하고 인덱스는 증가하지 않습니다.

첫 번째 예제의 코드는 "(123) 456-7890"을 10 진수 문자로 스캔하고 있으며, 첫 번째 문자에서 이미 실패하므로 scanCharactersFromSet : intoString에 대한 호출은 전달 된 strippedString 만 남겨두고 NO를 반환합니다. 코드는 strippedString을 할당하지 않은 채로 반환 값 확인을 완전히 무시합니다. 첫 번째 문자가 숫자 인 경우에도 해당 코드는 첫 번째 대시 나 뾰족한 부분까지 찾을 수있는 숫자 만 반환하므로 실패합니다.

NSScanner를 실제로 사용하려면 루프에 이와 같은 것을 넣고 NO 반환 값을 계속 확인하고 스캔 위치를 늘리면 다시 스캔 위치를 지정할 수 있습니다. isAtEnd 및 yada yada yada도 확인해야합니다. 요컨대, 작업에 대한 잘못된 도구입니다. 마이클의 솔루션이 더 좋습니다.


0

전화 추출을 검색하는 경우 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]);
            }
        }
    }
}

`


0

이 공통 작업을 단순화하기 위해 NSString에 범주를 만들었습니다.

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

0

현재 가장 좋은 방법은 다음과 같습니다.

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

0

당신은 단지 문자열에서 숫자를 잡기 위해 찾고 있다면, 당신은 할 수 확실히 그들을 구문 분석하는 정규 표현식을 사용합니다. Objective-C에서 정규 표현식을 수행하려면 RegexKit을 확인하십시오 . 편집 : @Nathan이 지적했듯이 NSScanner를 사용하는 것이 문자열에서 모든 숫자를 구문 분석하는 훨씬 간단한 방법입니다. 나는 그 옵션을 완전히 알지 못했기 때문에 그 제안을 제안합니다. (나는 정규식을 직접 사용하는 것을 좋아하지 않으므로 필요하지 않은 접근법을 선호합니다.)

표시 할 전화 번호의 형식을 지정하려면 NSNumberFormatter를 살펴보십시오 . 이 관련 SO 질문 을 읽고 팁을 얻으십시오. 전화 번호는 위치 및 / 또는 지역에 따라 다르게 형식이 지정됩니다.


아, 내가 좋은 전화 번호 포맷터와 파서를 개발하는 데 걸린 고통스러운 시간. 링크 된 스레드는 좋은 시작이지만, 표시하기 위해 전체 전화 번호를 포맷하는 일반적인 경우는 길지만 링크 된 스레드에서 언급 한 것처럼 Apple은 주소록 전화 번호 포맷터에 대한 액세스 권한을 제공하지 않습니다. 주소록 API에서 전화 번호가 표시되는 방식이 매우 일치하지 않습니다. 표시 할 전화 번호를 포맷하는 것보다 어려운 것은 두 전화 번호가 같은지 확인하는 것입니다. 최소한 OP의 질문이 가장 쉬운 문제입니다.
Rob Napier

기본 미국 중심의 구현에 만족하지 않으면 전화 번호 형식으로 연결되는 링크가 잘못되었다고 생각합니다. Apple에서 현지화 된 올바른 전화 번호 포맷터 대신,이를 올바르게 수행하는 유일한 방법은 포맷 템플릿을 장치에서 복사하고 (OS 2.x의 UIPhoneFormats.plist) 사용자의 로캘에 따라 템플릿을 직접 재생하는 것입니다. 이것은 사소한 일이 아닙니다.
Nathan de Vries

그래서 숫자 포맷터의 현지화에 대해 언급했습니다. 나는 그것에 대한 완전한 해결책의 형태를 게시하는 척하지 않았습니다. 훨씬 더 긴 토론이며 별도의 SO 질문으로 만드는 것이 더 합리적입니다.
퀸 테일러

0

스위프트 5

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

-1

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의 질문에 대답하지만 ",; * # +"와 같은 전화 번호 관련 문자를 남기도록 쉽게 수정할 수 있습니다.


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

];

간단하게 유지하십시오!


3
이것은 처음부터 끝까지 만 해당 문자를 잘라냅니다.
raidfive
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.