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]うまくいかないのか分かりますか?
Thomas Besnehard 2013年

1
@Tommecpe stringByTrimmingCharactersInSetは、文字列の最初と最後からのみ削除するため、最初の一致しない文字の後、または最後の一致しない文字の前には影響しません。
シモノボ2013年

数字とアルファベットだけを残したいのですが、どうすればよいですか?
ジャッキー2014年

1
上記の例の@Jackyは、[NSCharacterSet decimalDigitCharacterSet]数字と文字のみを含む別のものに置き換えます。あなたは、作成することによって、1を構築することができますNSMutableCharaterSetし、渡すdecimalDigitCharacterSetuppercaseLetterCharacterSetlowercaseLetterCharacterSetformUnionWithCharacterSet:。にletterCharacterSetはマークも含まれるため、小文字バージョンと大文字バージョンの使用に注意してください。
kadam 2014

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進数を表すすべての記号が含まれているため、Nathanリストのセットとは少し異なります。アプリケーションによっては、問題になることもありますが、一般的には問題がなく、中立的で、タイプするのが少し短いです。
Rob Napier、

この答えは実際には機能せず、問題に対する適切なアプローチではないことは確かです。実際にコードを試してみると(最初にNSLogの最初のパラメータの前に@を追加し、それをobjc文字列にします)、<null>を出力するか、クラッシュすることがわかります。どうして?以下の私の答えを参照してください。
ジャックナッティング

別の答えは必要ありません-それがコメントの目的です。Michael Pelz-Shermanのソリューションへの参照を含めて、ソリューションを更新しました。
Nathan de Vries、

4
これは複雑なことです。
ryyst 2010

63

受け入れられた答えは、求められているものに対して過剰です。これははるかに簡単です:

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

2
(現在)受け入れられている回答はこれとほぼ同じですが、13か月前に投稿されました。
カレブ

私がこれに答えたとき、それはこの答えを持っていませんでした。現在の回答はすでに提案されていて、見逃していたようですが、web.archive.org
web / 20101115214033 / http://stackoverflow.com/…– Yacine 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 2009

一番の答えは私にはうまくいきません。スキャナーが()または-に達すると停止します-この回答はうまくいきます!! 古き良きC !! ありがとう
Jeff

2
「+」は電話番号の文字として使用できることに注意してください。
Prcela、2011年

27

これは古くからの質問であり、有効な回答がありましたが、国際形式のサポートがありませんでした。シモノボのソリューションに基づいて、変更された文字セットにはプラス記号「+」が含まれています。国際電話番号もこの修正でサポートされています。

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 2013

これはうまくいきました!その働きを説明していただけますか?@alex
Jayprakash Dubey

11

これがSwiftバージョンです。

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

Swift 2.0:phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet()。invertedSet).joinWithSeparator( "")
iluvatar_GR

11

最も人気のある回答の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: "")

小数で区切られた記号を保持する方法はありますか?デバイスのデフォルト設定の関数としてのドット(またはコンマ)?あなたのソリューションは数字以外のすべてを排除します
ニコラス

5

例をありがとう。originalStringの文字の1つが数字のCharacterSetオブジェクト内に見つからない場合、scanLocationの増分が1つだけ不足しています。これを修正するために、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つのアプローチのプロファイリングにより、これは約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)

これは、最初と最後から数字以外の文字のみをトリミングします。
シェブカ2017年

1

迅速な4.1

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

0

ええと。最初の答えは私には全く間違っているようです。NSScannerは、実際には解析を目的としています。正規表現とは異なり、文字列を一度に1つの小さなチャンクとして解析します。これを文字列で初期化すると、取得した文字列に沿った距離のインデックスが維持されます。そのインデックスは常にその参照ポイントであり、ユーザーが指定するコマンドはすべてそのポイントを基準にしています。「OK、このセットの次の文字のチャンクをくれ」または「文字列で見つかった整数を教えて」と言うと、それらは現在のインデックスから始まり、一致しないものが見つかるまで進みます。一致。最初の文字が既に一致しない場合、メソッドはNOを返し、インデックスは増加しません。

最初の例のコードは、「(123)456-7890」の小数文字をスキャンしていますが、これは最初の文字から既に失敗しているため、scanCharactersFromSet:intoString:を呼び出すと、渡されたstrippedStringがそのまま残り、NOが返されます。コードは戻り値のチェックを完全に無視し、stripedStringを未割り当てのままにします。最初の文字が数字であったとしても、そのコードは失敗します。それは、最初のダッシュや括弧などまで、見つけた数字のみを返すためです。

NSScannerを本当に使用したい場合は、そのようなものをループに入れ、NO戻り値をチェックし続けることができます。それが得られた場合は、scanLocationをインクリメントして再度スキャンできます。また、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からの電話番号の表示方法に一貫性がありません。電話番号を表示用にフォーマットするよりも難しいのは、2つの電話番号が等しいかどうかを判断することだけです。少なくともOPの質問は、最も簡単な問題です。
Rob Napier、

米国を中心とする原始的な実装に満足していない限り、電話番号のフォーマットへのリンクは誤解を招くと思います。Appleの適切なローカライズされた電話番号フォーマッタの代わりに、これを正しく行う唯一の方法は、デバイスからフォーマットテンプレート(OS 2.xのUIPhoneFormats.plist)をコピーし、ユーザーのロケールに応じて自分でテンプレートを再現することです。これは重要な作業です。
Nathan de Vries、

そのため、数値フォーマッターのローカライズについて説明しました。私はそのための完全な解決策の形を投稿するつもりはありませんでした。それははるかに長い議論であり、個別のSOの質問にする方が理にかなっています。
Quinn Taylor、


-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 2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.