ฉันมี NSString (หมายเลขโทรศัพท์) ที่มีวงเล็บและยัติภังค์เพราะมีการจัดรูปแบบหมายเลขโทรศัพท์ ฉันจะลบอักขระทั้งหมดยกเว้นตัวเลขออกจากสตริงได้อย่างไร
ฉันมี NSString (หมายเลขโทรศัพท์) ที่มีวงเล็บและยัติภังค์เพราะมีการจัดรูปแบบหมายเลขโทรศัพท์ ฉันจะลบอักขระทั้งหมดยกเว้นตัวเลขออกจากสตริงได้อย่างไร
คำตอบ:
คำถามเก่า แต่เรื่อง:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
มันจะระเบิดสตริงต้นทางในชุดที่ไม่ใช่ตัวเลขจากนั้นประกอบอีกครั้งโดยใช้ตัวคั่นสตริงที่ว่างเปล่า ไม่มีประสิทธิภาพเท่ากับการเลือกผ่านตัวอักษร แต่มีขนาดกะทัดรัดกว่าในโค้ด
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
ไม่ทำงาน?
[NSCharacterSet decimalDigitCharacterSet]
ด้วยอันที่มีตัวเลขและตัวอักษรเท่านั้น คุณสามารถสร้างหนึ่งโดยการสร้าง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
ดังนั้นคุณอาจต้องการดูสิ่งนั้น
คำตอบที่ยอมรับคือ overkill สำหรับสิ่งที่ถูกถาม ง่ายกว่านี้มาก:
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
เป็นสิ่งที่ดี แต่รหัสไม่ทำงานสำหรับฉันใน iPhone 3.0 SDK
ถ้าฉันกำหนด strippedString ตามที่คุณแสดงที่นี่ฉันจะได้รับBAD ACCESS error
เมื่อพยายามพิมพ์หลังจากscanCharactersFromSet:intoString
โทร
ถ้าฉันทำเช่นนั้น:
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
ฉันท้ายด้วยสตริงว่างเปล่า แต่รหัสไม่ผิดพลาด
ฉันต้องหันไปหาซีเก่าดีแทน:
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
แต่นี้เป็นคำถามเดิมกับคำตอบที่ทำงานผมพลาดการสนับสนุนรูปแบบสากล ขึ้นอยู่กับการแก้ปัญหาของ 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 เป็นรูปแบบหมายเลขโทรศัพท์ระหว่างประเทศทั่วไป
นี่คือเวอร์ชั่น Swift ของสิ่งนี้
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
คำตอบที่ได้รับความนิยมมากที่สุด:
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: "")
ขอบคุณสำหรับตัวอย่าง มีเพียงสิ่งเดียวที่ขาดการเพิ่มขึ้นของ scanLocation ในกรณีที่ไม่พบอักขระตัวใดตัวหนึ่งใน originalString ภายในวัตถุหมายเลข CharacterSet ฉันได้เพิ่มคำสั่งอื่น {} เพื่อแก้ไขปัญหานี้
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"
ยอมรับหมายเลขโทรศัพท์มือถือเท่านั้น
NSString * strippedNumber = [mobileNumber stringByReplacingOccurrencesOfString:@"[^0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [mobileNumber length])];
อาจเป็นที่น่าสังเกตว่าคำตอบที่ได้รับการยอมรับ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
คุณสามารถใช้นิพจน์ปกติกับสตริงที่ไม่แน่นอน
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:
@"[^\\d]"
options:0
error:nil];
[regex replaceMatchesInString:str
options:0
range:NSMakeRange(0, str.length)
withTemplate:@""];
สร้างโซลูชันยอดนิยมเป็นหมวดหมู่เพื่อช่วยแก้ไขปัญหาที่กว้างขึ้น:
อินเตอร์เฟซ:
@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
การใช้งาน:
NSString *strippedString =
[originalString stringByReplacingCharactersNotInSet:
[NSCharacterSet setWithCharactersInString:@"01234567890"
with:@""];
let notNumberCharacters = NSCharacterSet.decimalDigits.inverted
let intString = yourString.trimmingCharacters(in: notNumberCharacters)
รวดเร็ว 4.1
var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)
หนอ คำตอบแรกดูเหมือนผิดทั้งหมดสำหรับฉัน NSScanner มีความหมายจริงๆสำหรับการแยกวิเคราะห์ ไม่เหมือนกับ regex คุณแยกวิเคราะห์สตริงทีละน้อย ๆ คุณเริ่มต้นมันด้วยสตริงและมันจะเก็บดัชนีว่าระยะทางของสตริงนั้นยาวแค่ไหน ดัชนีนั้นเป็นจุดอ้างอิงเสมอและคำสั่งใด ๆ ที่คุณให้มานั้นจะสัมพันธ์กับจุดนั้น คุณบอกมันว่า "โอเคให้ฉันดูตัวละครต่อไปในชุดนี้" หรือ "ให้จำนวนเต็มที่คุณเจอในสตริง" และเริ่มจากดัชนีปัจจุบันแล้วไปข้างหน้าจนกว่าพวกเขาจะพบสิ่งที่ไม่ การจับคู่. หากอักขระตัวแรกที่ไม่ตรงกันแล้วเมธอดจะส่งคืน NO และดัชนีจะไม่เพิ่มขึ้น
โค้ดในตัวอย่างแรกคือการสแกน "(123) 456-7890" สำหรับอักขระทศนิยมซึ่งล้มเหลวจากอักขระตัวแรกดังนั้นการเรียกใช้ scanCharactersFromSet: intoString: จะทำให้การลอกผ่านสตริงเป็นแบบแยกและส่งคืน NO; รหัสไม่สนใจการตรวจสอบค่าส่งคืนทั้งหมดทำให้ strippedString ไม่ถูกมอบหมาย แม้ว่าตัวอักษรตัวแรกจะเป็นตัวเลข แต่รหัสนั้นก็จะล้มเหลวเพราะมันจะคืนค่าตัวเลขที่พบจนกระทั่งตัวแรกหรือตัวย่อหรืออะไรก็ตาม
หากคุณต้องการใช้ NSScanner จริงๆคุณสามารถใส่สิ่งนั้นลงในลูปและทำการตรวจสอบค่า NO return และถ้าคุณได้รับสิ่งนั้นคุณสามารถเพิ่มตำแหน่งสแกนและสแกนอีกครั้ง และคุณต้องตรวจสอบ 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
ฉันคิดว่าวิธีที่ดีที่สุดในปัจจุบันคือ:
phoneNumber.replacingOccurrences(of: "\\D",
with: "",
options: String.CompareOptions.regularExpression)
หากคุณเพียงแค่ต้องการจับตัวเลขจากสตริงคุณสามารถใช้การแสดงผลปกติเพื่อแยกพวกเขาออก สำหรับการทำ regex ใน Objective-C, ตรวจสอบRegexKit แก้ไข: ตามที่ @Nathan ชี้ให้เห็นการใช้ NSScanner เป็นวิธีที่ง่ายกว่ามากในการวิเคราะห์ตัวเลขทั้งหมดจากสตริง ฉันไม่รู้ตัวเลือกทั้งหมดเลยดังนั้นอุปกรณ์สำหรับเขาที่แนะนำมัน (ฉันไม่ชอบใช้ regex ด้วยตัวเองดังนั้นฉันจึงชอบวิธีที่ไม่ต้องการใช้)
หากคุณต้องการจัดรูปแบบหมายเลขโทรศัพท์สำหรับการแสดงผลของมันคุ้มค่าการดูที่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"]