NSString'den sayılar hariç tümünü kaldır


157

Bazı telefon numaraları biçimlendirildiği için bazı parantez ve kısa çizgilerle bir NSString (telefon numarası) var. Dizeden sayılar dışındaki tüm karakterleri nasıl kaldırabilirim?

Yanıtlar:


375

Eski soru, ama nasıl?

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

Rakam olmayan kümedeki kaynak dizgiyi patlar, sonra boş bir dizgi ayırıcısı kullanarak bunları yeniden birleştirir. Karakterleri seçmek kadar verimli değil, kodda çok daha kompakt.


6
Teşekkürler! Diğer yeni başlayanlar için, kendi özel NSCharacterSet'inizi oluşturarak oluşturabilirsinizNSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]
guptron

1
Çok teşekkür ederim ! Sadece merakım için neden NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]işe yaramadığına dair bir fikrin var mı?
Thomas Besnehard

1
@Tommecpe stringByTrimmingCharactersInSet yalnızca dizenin başından ve sonundan kaldırır, bu nedenle ilk eşleşmeyen karakterden veya son eşleşmeyen karakterden önce etkilenmez.
simonobo

sadece sayı ve alfabe tutmak istiyorum, nasıl yapabilirim?
Jacky

1
@ Yukarıdaki örnekte Jacky yerine [NSCharacterSet decimalDigitCharacterSet]yalnızca rakam ve harf içeren bir başkası kullanabilirsiniz. Bir oluşturarak birini inşa edebilir NSMutableCharaterSetve o sırada geçen decimalDigitCharacterSet, uppercaseLetterCharacterSetve lowercaseLetterCharacterSetiçin formUnionWithCharacterSet:. Not letterCharacterSetyanı işaretleri içermektedir, düşük- ve büyük versiyonlarının dolayısıyla kullanımı.
kadam

75

Diğer cevapların önerdiği gibi normal ifadeler kitaplığı kullanmaya gerek yoktur - peşinde olduğunuz sınıf çağrılır NSScanner. Aşağıdaki gibi kullanılır:

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"

DÜZENLE: Kodu güncelledim çünkü orijinal kafamın üst kısmından yazıldı ve insanları doğru yönde göstermenin yeterli olacağını düşündüm. İnsanların koddan sonra olduğu gibi doğrudan uygulamalarına kopyalayıp yapıştırabilirler.

Ayrıca Michael Pelz-Sherman'ın çözümünün kullanmaktan daha uygun olduğunu kabul ediyorum NSScanner, bu yüzden buna bir göz atmak isteyebilirsiniz.


+1 Soruyu doğrudan ele alan iyi cevap. Bu yaklaşımı savunmak için cevabımı düzenledim, ancak ikinci yarıyı olduğu gibi bırakıyorum, çünkü yine de yardımcı oluyor). (Sonra, aşağı okurken yapıcı bir yorum bırakabilir misiniz, sadece daha sonra okuyucular içinse?)
Quinn Taylor

4
Size tüm ondalık basamakları verecek bir + decimalDigitCharacterSet NSCharacterSet yöntemi olduğunu bilmek kullanışlı olabilir. Bu, ayarlanan Nathan listelerinden biraz farklıdır, çünkü örneğin Arapça-Hintçe rakamlar (١٢٣٤٥ vb.) Dahil olmak üzere ondalık sayıları temsil eden tüm sembolleri içerir. Uygulamanıza bağlı olarak, bu bazen bir sorun olabilir, ancak genellikle iyi veya nötr ve yazmak için biraz daha kısa olabilir.
Rob Napier

Bu cevabın gerçekten işe yaramadığından ve soruna gerçekten doğru bir yaklaşım olmadığından eminim. Kodu gerçekten gösterildiği gibi denerseniz (ilk olarak NSLog'a ilk paramdan önce bir @ ekleyerek onu bir objc dizesi yaparsanız), kodun <boş> veya çöktüğünü görürsünüz. Neden? Cevabımı aşağıda görebilirsiniz.
Jack Nutting

Başka bir cevaba gerek yok - yorumlar bunun için. Michael Pelz-Sherman'ın çözümüne bir referans da dahil olmak üzere çözümü güncelledim.
Nathan de Vries

4
Bu karmaşık bir şey.
ryyst

63

Kabul edilen cevap, sorulan soru için aşırıya kaçmaktır. Bu çok daha basit:

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

2
(Şu anda) kabul edilen cevap aşağı yukarı aynıdır, ancak 13 ay önce yayınlanmıştır.
Caleb

Bunu cevapladığım zaman, bu cevabı yoktu. Şu anki cevap zaten önerilmiş gibi görünsem de
Yacine Filali

30

Bu harika, ancak kod iPhone 3.0 SDK'da benim için çalışmıyor.

Burada gösterildiği gibi strippedString öğesini tanımlarsam BAD ACCESS error, scanCharactersFromSet:intoStringçağrıdan sonra yazdırmaya çalışırken bir an alırım .

Eğer öyle yaparsam:

NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];

Ben boş bir dize ile sonunda, ama kod çökmez.

Bunun yerine iyi eski C başvurmak zorunda kaldı:

for (int i=0; i<[phoneNumber length]; i++) {
    if (isdigit([phoneNumber characterAtIndex:i])) {
        [strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
    }
}

3.0 kullanıyorum ve bu benim için çalışıyor. Vries'in daha popüler cevabı işe yaramadı.
Neo42

Bir numaralı cevap benim için çalışmayacak. Tarayıcı bir () veya - ulaştığında durur - Bu cevap harika çalışıyor !! İyi eski C !! Teşekkür ederim
Jeff

2
Telefon numarası için yalnızca '+' karakterine izin verilmesi gerektiğini unutmayın.
Prcela

27

Bu, çalışma cevapları ile eski bir soru olmasına rağmen, uluslararası format desteğini kaçırdım . Simonobo'nun çözümüne dayanarak, değiştirilen karakter seti artı işareti "+" içerir. Uluslararası telefon numaraları da bu değişiklikle desteklenmektedir.

NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
              [[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
              invertedSet]] 
              componentsJoinedByString:@""];

Swift ifadeleri

var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")

Hangi ortak uluslararası telefon numarası biçimi olarak +12345671000 verir.


2
Bu, özellikle uluslararası telefon numaraları için artı işaretine ihtiyacınız varsa, listedeki en iyi çözümdür.
UXUiOS

Bazı nedenlerden dolayı, tersine çevrilmiş bir karakter seti kullanmak beni performans açısından korkutuyor. Bunun asılsız bir korku olup olmadığını bilen var mı?
devios1

Bu işe yaradı! Çalışmasını açıklayabilir misiniz? @alex
Jayprakash Dubey

11

İşte bunun Swift versiyonu.

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 (). İnvertedSet) .joinWithSeparator ("")
iluvatar_GR

11

En popüler cevabın hızlı versiyonu:

var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))

Düzenleme: Sözdizimi for Swift 2

let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")

Düzenleme: Sözdizimi for Swift 3

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

ondalık işareti ayrılmış sembolü tutmanın bir yolu var mı? Cihazın varsayılan ayarlarının bir fonksiyonu olarak nokta (veya virgül)? Çözümünüz sayılar dışında her şeyi ortadan kaldırıyor
Nicholas

5

Örnek için teşekkürler. OriginalString öğesindeki karakterlerden birinin CharacterSet nesnesinin içinde bulunmaması durumunda, scanLocation öğesinin artışını içermeyen tek bir şey vardır. Bunu düzeltmek için başka bir {} ifadesi ekledim.

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

Sadece cep telefonu numarasını kabul eder

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

3

Kabul edilen componentsSeparatedByCharactersInSet:ve componentsJoinedByString:temelli cevabın bellek açısından verimli bir çözüm olmadığını belirtmek gerekir . Karakter kümesi, bir dizi ve yeni bir dize için bellek ayırır. Bunlar yalnızca geçici ayırmalar olsa bile, birçok dizeyi bu şekilde işlemek belleği hızla doldurabilir.

Bellek dostu bir yaklaşım, dizenin değişebilir bir kopyası üzerinde çalışmak olacaktır. NSString üzerinden bir kategoride:

-(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];
}

İki yaklaşımın profilini çıkarmak, bunu yaklaşık 2/3 daha az bellek kullanarak göstermiştir.


2

Değişken dizede normal ifadeyi kullanabilirsiniz:

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

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

1

Daha geniş sorunlara yardımcı olmak için en iyi çözümü kategori olarak oluşturdu:

Arayüz:

@interface NSString (easyReplace)
- (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set 
                                             with:(NSString *)string;
@end

implemenation:

@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

Kullanımı:

NSString *strippedString = 
 [originalString stringByReplacingCharactersNotInSet:
   [NSCharacterSet setWithCharactersInString:@"01234567890" 
                                        with:@""];

1

Hızlı 3

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

Bu yalnızca rakam olmayan karakterleri başlangıçtan ve sondan keser.
Shebuka

1

hızlı 4.1

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

0

Um. İlk cevap benim için tamamen yanlış görünüyor. NSScanner gerçekten ayrıştırma amaçlıdır. Normal ifadenin aksine, dizeyi her seferinde küçük bir yığın halinde ayrıştırır. Bir dize ile başlatırsınız ve dize boyunca ne kadar ilerlediğinin bir dizinini tutar; Bu dizin her zaman onun referans noktasıdır ve ona verdiğiniz komutlar o noktaya göredir. "Tamam, bana bu setteki bir sonraki karakter grubunu ver" veya "dizede bulduğunuz tamsayıyı ver" deyin ve bunlar geçerli dizinde başlıyor ve olmayan bir şey bulana kadar ilerliyor eşleşme. İlk karakter zaten eşleşmiyorsa, yöntem NO döndürür ve dizin artmaz.

İlk örnekteki kod, ilk karakterden zaten başarısız olan ondalık karakterler için "(123) 456-7890" taramasıdır, bu nedenle scanCharactersFromSet: intoString: iletilen strippedString işlevini yalnız bırakır ve NO döndürür; Kod, strippedString öğesinin atanmamış kalmasını sağlayarak dönüş değerini kontrol etmeyi tamamen yoksayar. İlk karakter bir rakam olsa bile, bu kod başarısız olur, çünkü yalnızca ilk tire veya paren ya da herhangi bir şeye kadar bulduğu rakamları döndürür.

NSScanner'ı gerçekten kullanmak istiyorsanız, bir döngüye böyle bir şey koyabilir ve NO dönüş değerini kontrol etmeye devam edebilirsiniz ve bunu elde ederseniz scanLocation'ı artırabilir ve tekrar tarayabilirsiniz; ayrıca isAtEnd ve yada yada yada'yı kontrol etmelisiniz. Kısacası, iş için yanlış bir araç. Michael'ın çözümü daha iyi.


0

Telefon ayıklama arayanlar için NSDataDetector kullanarak telefon numaralarını bir metinden ayıklayabilirsiniz, örneğin:

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

Bu ortak işlemi basitleştirmek için NSString'de bir kategori oluşturdum.

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

Şu anda en iyi yol olduğunu düşünüyorum:

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

0

Sadece sayıları dizeden almak istiyorsanız, , onları düzenli olarak ifade etmek için ayrıştırabilirsiniz. Objective-C'de normal ifade yapmak için RegexKit'e bakın . Düzenleme: @Nathan işaret ettiği gibi, NSScanner kullanmak bir dizeden tüm sayıları ayrıştırmak için çok daha basit bir yoludur. Bu seçeneğin tamamen farkında değildim, bu yüzden önerdiği için ona destek oldu. (Normal ifadeyi kendim kullanmayı bile sevmiyorum, bu yüzden onları gerektirmeyen yaklaşımları tercih ederim.)

Telefon numaralarını görüntülemek üzere biçimlendirmek istiyorsanız, NSNumberFormatter'a . Bunu yapmayla ilgili ipuçları için bu ilgili SO sorusunu okumanızı öneririz . Telefon numaralarının konuma ve / veya yerel ayara bağlı olarak farklı biçimlendirildiğini unutmayın.


Oh iyi saatler sayı biçimlendiriciler ve ayrıştırıcılar geliştirmek için harcadım acı saatler. Bağlantılı iş parçacıkları iyi bir başlangıçtır, ancak genel telefon numaralarını görüntüleme için biçimlendirmenin genel durumu uzun bir yoldur ve bağlı iş parçacıklarında belirtildiği gibi, Apple size Adres Defteri telefon numarası biçimlendiricilerine erişim vermez ve Adres Defteri API'sından telefon numaralarının sunulma biçiminde tutarsız. Bir telefon numarasını görüntülemek için biçimlendirmekten daha zor olan tek şey, iki telefon numarasının eşit olup olmadığını belirlemektir. En azından OP'nin sorunu sorunların en kolayı.
Rob Napier

İlkel, ABD merkezli bir uygulamadan memnun değilseniz, telefon numaralarını biçimlendirme bağlantılarının yanıltıcı olduğuna inanıyorum. Apple'dan uygun bir yerelleştirilmiş telefon numarası biçimlendiricisinin yerine, bunu düzgün bir şekilde yapmanın tek yolu, biçimlendirme şablonlarını cihazdan (OS 2.x'te UIPhoneFormats.plist) kopyalamak ve kullanıcıların yerel ayarlarına bağlı olarak şablonları kendiniz yeniden oluşturmaktır. Bu önemsiz olmayan bir görevdir.
Nathan de Vries

Bu yüzden sayı biçimlendiricilerinin yerelleştirilmesinden bahsettim. Bunun için tam bir çözüm yolu gibi davranmadım - çok daha uzun bir tartışma ve ayrı bir SO sorusu yapmak daha mantıklı olurdu.
Quinn Taylor

0

Hızlı 5

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

-1

Jon Vogel'in buradaki cevabına dayanarak, bazı temel testlerle birlikte bir Swift String uzantısıdır.

import Foundation
extension String {
    func stringByRemovingNonNumericCharacters() -> String {
        return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
    }
}

Ve en azından temel işlevselliği kanıtlayan bazı testler:

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 == "")
    }
}

Bu OP'nin sorusunu yanıtlar, ancak ",; * # +" gibi telefon numaralarıyla ilgili karakterlerde bırakmak için kolayca değiştirilebilir.


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

];

Basit tutun!


3
bu yalnızca bu karakterleri başlangıçtan ve bitişten keser.
baskın
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.