回答:
古い質問ですが、どうですか:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
非数字のセットでソース文字列を分解し、空の文字列セパレータを使用してそれらを再構成します。文字を選択するほど効率的ではありませんが、コードははるかにコンパクトです。
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
うまくいかないのか分かりますか?
[NSCharacterSet decimalDigitCharacterSet]
数字と文字のみを含む別のものに置き換えます。あなたは、作成することによって、1を構築することができます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]];
}
}
これは古くからの質問であり、有効な回答がありましたが、国際形式のサポートがありませんでした。シモノボのソリューションに基づいて、変更された文字セットにはプラス記号「+」が含まれています。国際電話番号もこの修正でサポートされています。
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が生成されます。
これが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: "")
例をありがとう。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"
承認さ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少ないメモリを使用してこれを示しています。
より広範な問題を解決するために、カテゴリとしてトップのソリューションを構築しました。
インターフェース:
@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は、実際には解析を目的としています。正規表現とは異なり、文字列を一度に1つの小さなチャンクとして解析します。これを文字列で初期化すると、取得した文字列に沿った距離のインデックスが維持されます。そのインデックスは常にその参照ポイントであり、ユーザーが指定するコマンドはすべてそのポイントを基準にしています。「OK、このセットの次の文字のチャンクをくれ」または「文字列で見つかった整数を教えて」と言うと、それらは現在のインデックスから始まり、一致しないものが見つかるまで進みます。一致。最初の文字が既に一致しない場合、メソッドはNOを返し、インデックスは増加しません。
最初の例のコードは、「(123)456-7890」の小数文字をスキャンしていますが、これは最初の文字から既に失敗しているため、scanCharactersFromSet:intoString:を呼び出すと、渡されたstrippedStringがそのまま残り、NOが返されます。コードは戻り値のチェックを完全に無視し、stripedStringを未割り当てのままにします。最初の文字が数字であったとしても、そのコードは失敗します。それは、最初のダッシュや括弧などまで、見つけた数字のみを返すためです。
NSScannerを本当に使用したい場合は、そのようなものをループに入れ、NO戻り値をチェックし続けることができます。それが得られた場合は、scanLocationをインクリメントして再度スキャンできます。また、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の質問を読むことをお勧めします。電話番号の形式は、場所やロケールによって異なります。
スウィフト5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
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"]