Tôi có một NSString (số điện thoại) với một số dấu ngoặc đơn và dấu gạch nối vì một số số điện thoại được định dạng. Làm thế nào tôi có thể loại bỏ tất cả các ký tự ngoại trừ số từ chuỗi?
Tôi có một NSString (số điện thoại) với một số dấu ngoặc đơn và dấu gạch nối vì một số số điện thoại được định dạng. Làm thế nào tôi có thể loại bỏ tất cả các ký tự ngoại trừ số từ chuỗi?
Câu trả lời:
Câu hỏi cũ, nhưng làm thế nào về:
NSString *newString = [[origString componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
Nó phát nổ chuỗi nguồn trên tập hợp các chữ số không, sau đó ghép lại chúng bằng cách sử dụng một dấu tách chuỗi trống. Không hiệu quả như chọn qua các ký tự, nhưng mã nhỏ gọn hơn nhiều.
NSString *pureNumbers = [pureNumbers stringByTrimmingCharactersInSet: [NSCharacterSet decimalDigitCharacterSet] invertedSet]
Không hoạt động không?
[NSCharacterSet decimalDigitCharacterSet]
bằng một cái khác chỉ chứa số và chữ cái. Bạn có thể xây dựng một bằng cách tạo một NSMutableCharaterSet
và vượt qua a decimalDigitCharacterSet
, uppercaseLetterCharacterSet
và lowercaseLetterCharacterSet
đến formUnionWithCharacterSet:
. Lưu ý letterCharacterSet
bao gồm cả nhãn hiệu, do đó sử dụng các phiên bản chữ thường và chữ hoa.
Không cần sử dụng thư viện biểu thức chính quy như các câu trả lời khác gợi ý - lớp bạn theo sau được gọi NSScanner
. Nó được sử dụng như sau:
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"
EDIT: Tôi đã cập nhật mã bởi vì bản gốc đã được viết ra khỏi đỉnh đầu của tôi và tôi nghĩ rằng nó sẽ đủ để chỉ cho mọi người đi đúng hướng. Có vẻ như mọi người đang theo mã họ chỉ có thể sao chép-dán thẳng vào ứng dụng của họ.
Tôi cũng đồng ý rằng giải pháp của Michael Pelz-Sherman phù hợp hơn là sử dụng NSScanner
, vì vậy bạn có thể muốn xem xét điều đó.
Câu trả lời được chấp nhận là quá mức cho những gì đang được hỏi. Điều này đơn giản hơn nhiều:
NSString *pureNumbers = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
Điều này thật tuyệt, nhưng mã không hoạt động với tôi trên SDK iPhone 3.0.
Nếu tôi xác định tước sọc khi bạn hiển thị ở đây, tôi sẽ nhận được BAD ACCESS error
khi cố gắng in nó sau scanCharactersFromSet:intoString
cuộc gọi.
Nếu tôi làm như vậy:
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
Tôi kết thúc với một chuỗi rỗng, nhưng mã không bị lỗi.
Thay vào đó, tôi đã phải dùng đến C cũ tốt:
for (int i=0; i<[phoneNumber length]; i++) {
if (isdigit([phoneNumber characterAtIndex:i])) {
[strippedString appendFormat:@"%c",[phoneNumber characterAtIndex:i]];
}
}
Mặc dù đây là một câu hỏi cũ với câu trả lời làm việc, tôi đã bỏ lỡ hỗ trợ định dạng quốc tế . Dựa trên giải pháp của simonobo, bộ ký tự được thay đổi bao gồm dấu cộng "+". Số điện thoại quốc tế cũng được hỗ trợ bởi sửa đổi này.
NSString *condensedPhoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]
invertedSet]]
componentsJoinedByString:@""];
Các biểu thức Swift là
var phoneNumber = " +1 (234) 567-1000 "
var allowedCharactersSet = NSMutableCharacterSet.decimalDigitCharacterSet()
allowedCharactersSet.addCharactersInString("+")
var condensedPhoneNumber = phoneNumber.componentsSeparatedByCharactersInSet(allowedCharactersSet.invertedSet).joinWithSeparator("")
Mà mang lại +12345671000 như một định dạng số điện thoại quốc tế phổ biến.
Đây là phiên bản Swift của cái này.
import UIKit
import Foundation
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Phiên bản Swift của câu trả lời phổ biến nhất:
var newString = join("", oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
Chỉnh sửa: Cú pháp cho Swift 2
let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
Chỉnh sửa: Cú pháp cho Swift 3
let newString = oldString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Cảm ơn ví dụ. Nó chỉ có một thứ thiếu sự gia tăng của scanLocation trong trường hợp một trong các ký tự trong gốcString không được tìm thấy bên trong các đối tượng Ký tự số. Tôi đã thêm một câu lệnh {} khác để sửa lỗi này.
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"
Có thể đáng lưu ý rằng sự chấp nhận componentsSeparatedByCharactersInSet:
vàcomponentsJoinedByString:
câu trả lời dựa trên không phải là một giải pháp hiệu quả bộ nhớ. Nó phân bổ bộ nhớ cho bộ ký tự, cho một mảng và cho một chuỗi mới. Ngay cả khi đây chỉ là phân bổ tạm thời, xử lý nhiều chuỗi theo cách này có thể nhanh chóng lấp đầy bộ nhớ.
Một cách tiếp cận thân thiện với bộ nhớ sẽ là vận hành trên một bản sao có thể thay đổi của chuỗi. Trong một danh mục trên 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];
}
Cấu hình hai cách tiếp cận đã cho thấy điều này bằng cách sử dụng khoảng 2/3 bộ nhớ.
Xây dựng giải pháp hàng đầu như một danh mục để giúp giải quyết các vấn đề rộng hơn:
Giao diện:
@interface NSString (easyReplace)
- (NSString *)stringByReplacingCharactersNotInSet:(NSCharacterSet *)set
with:(NSString *)string;
@end
Thực hiện:
@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
Sử dụng:
NSString *strippedString =
[originalString stringByReplacingCharactersNotInSet:
[NSCharacterSet setWithCharactersInString:@"01234567890"
with:@""];
nhanh 4,1
var str = "75003 Paris, France"
var stringWithoutDigit = (str.components(separatedBy:CharacterSet.decimalDigits)).joined(separator: "")
print(stringWithoutDigit)
Ừm. Câu trả lời đầu tiên dường như hoàn toàn sai với tôi. NSScanner thực sự có nghĩa là để phân tích cú pháp. Không giống như regex, nó có một lần phân tích cú pháp chuỗi nhỏ. Bạn khởi tạo chuỗi đó bằng một chuỗi và nó duy trì một chỉ số về khoảng cách dọc theo chuỗi; Chỉ mục đó luôn là điểm tham chiếu của nó và bất kỳ lệnh nào bạn đưa ra đều liên quan đến điểm đó. Bạn nói với nó, "ok, đưa cho tôi đoạn ký tự tiếp theo trong tập hợp này" hoặc "đưa cho tôi số nguyên bạn tìm thấy trong chuỗi" và chúng bắt đầu ở chỉ mục hiện tại và tiến về phía trước cho đến khi chúng tìm thấy thứ gì đó không trận đấu. Nếu chính ký tự đầu tiên không khớp, thì phương thức trả về NO và chỉ mục không tăng.
Mã trong ví dụ đầu tiên là quét "(123) 456-7890" cho các ký tự thập phân, đã bị lỗi từ ký tự đầu tiên, do đó, lệnh gọi để quétChar characterFromset: inString: để lại một mình bị tước đi và trả về NO; Mã hoàn toàn bỏ qua việc kiểm tra giá trị trả về, không để lại chuỗi bị tước. Ngay cả khi ký tự đầu tiên là một chữ số, mã đó sẽ thất bại, vì nó sẽ chỉ trả về các chữ số mà nó tìm thấy cho đến dấu gạch đầu tiên hoặc paren hoặc bất cứ thứ gì.
Nếu bạn thực sự muốn sử dụng NSScanner, bạn có thể đặt một cái gì đó tương tự vào một vòng lặp và tiếp tục kiểm tra giá trị trả về KHÔNG, và nếu bạn nhận được rằng bạn có thể tăng quétLocation và quét lại; và bạn cũng phải kiểm tra isAtEnd và yada yada yada. Tóm lại, sai công cụ cho công việc. Giải pháp của Michael là tốt hơn.
Đối với những người tìm kiếm trích xuất điện thoại, bạn có thể trích xuất các số điện thoại từ một văn bản bằng NSDataDetector, ví dụ:
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]);
}
}
}
}
`
Tôi đã tạo một danh mục trên NSString để đơn giản hóa thao tác phổ biến này.
@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
Nếu bạn chỉ muốn lấy các số từ chuỗi, bạn chắc chắn có thể sử dụng các biểu thức thông thường để phân tích chúng. Để thực hiện regex trong Objective-C, hãy xem RegexKit . Chỉnh sửa: Như @Nathan chỉ ra, sử dụng NSScanner là cách đơn giản hơn nhiều để phân tích tất cả các số từ một chuỗi. Tôi hoàn toàn không biết về lựa chọn đó, vì vậy các đạo cụ cho anh ấy đã gợi ý nó. (Tôi thậm chí không thích sử dụng regex cho mình, vì vậy tôi thích các phương pháp không yêu cầu chúng.)
Nếu bạn muốn định dạng số điện thoại để hiển thị, đáng để xem qua NSNumberFormatter . Tôi đề nghị bạn đọc qua câu hỏi SO liên quan này để biết các mẹo làm như vậy. Hãy nhớ rằng các số điện thoại được định dạng khác nhau tùy thuộc vào vị trí và / hoặc miền địa phương.
Swift 5
let newString = origString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Dựa trên câu trả lời của Jon Vogel ở đây, đây là phần mở rộng Chuỗi Swift cùng với một số thử nghiệm cơ bản.
import Foundation
extension String {
func stringByRemovingNonNumericCharacters() -> String {
return self.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
}
}
Và một số thử nghiệm chứng minh ít nhất chức năng cơ bản:
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 == "")
}
}
Điều này trả lời câu hỏi của OP nhưng có thể dễ dàng sửa đổi để để lại các ký tự liên quan đến số điện thoại như ",; * # +"
NSString *originalPhoneNumber = @"(123) 123-456 abc";
NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
NSString *trimmedPhoneNumber = [originalPhoneNumber stringByTrimmingCharactersInSet:numbers];
];
Giữ cho nó đơn giản!
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"charactersGoHere"]