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?
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:
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.
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
işe yaramadığına dair bir fikrin var mı?
[NSCharacterSet decimalDigitCharacterSet]
yalnızca rakam ve harf içeren bir başkası kullanabilirsiniz. Bir oluşturarak birini inşa edebilir NSMutableCharaterSet
ve o sırada geçen decimalDigitCharacterSet
, uppercaseLetterCharacterSet
ve lowercaseLetterCharacterSet
için formUnionWithCharacterSet:
. Not letterCharacterSet
yanı işaretleri içermektedir, düşük- ve büyük versiyonlarının dolayısıyla kullanımı.
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.
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:@""];
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]];
}
}
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.
İşte bunun Swift versiyonu.
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
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: "")
Ö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"
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.
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:@""];
hızlı 4.1
var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)
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.
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]);
}
}
}
}
'
Bu ortak işlemi basitleştirmek için NSString'de bir kategori oluşturdum.
@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
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.
Hızlı 5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
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.
NSString *originalPhoneNumber = @"(123) 123-456 abc";
NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
NSString *trimmedPhoneNumber = [originalPhoneNumber stringByTrimmingCharactersInSet:numbers];
];
Basit tutun!
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]