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, uppercaseLetterCharacterSet및 lowercaseLetterCharacterSet에 formUnionWithCharacterSet:. 주 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.