Удалить все, кроме чисел из NSString



У меня есть NSString (номер телефона) с некоторыми скобками и дефисами, поскольку некоторые номера телефонов отформатированы. Как бы я удалил все символы, кроме чисел из строки?

719   21  

21 ответов:

старый вопрос, но как насчет:

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

он взрывает исходную строку на наборе нецифровых символов, а затем повторно собирает их с помощью пустого разделителя строк. Не так эффективно, как перебирать символы, но гораздо компактнее в коде.

нет необходимости использовать библиотеку регулярных выражений, как предлагают другие ответы - класс, который вы ищете, называется 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"

EDIT: я обновил код, потому что оригинал был списан с моей головы, и я решил, что этого будет достаточно, чтобы указать людям в правильном направлении. Кажется, что люди после кода они могут просто скопировать-вставить прямо в свое приложение.

Я также согласен, что Решение Майкла Пельца-Шермана более уместно, чем использование 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]];
    }
}

хотя это старый вопрос с рабочими ответами, я пропустил поддержка международного формата. Основанный на решении 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 в качестве общего международного формата телефонного номера.

вот быстрая версия этого.

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: "")

Спасибо за пример. У него есть только одна вещь, отсутствующая приращение scanLocation в случае, если один из символов в originalString не найден внутри объекта набора символов numbers. Я добавил еще {} заявление, чтобы исправить это.

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

исполнение:

@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:@""];

Swift 3

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

Если вы просто хотите, чтобы захватить номера из строки, вы может конечно использовать регулярные выражения, чтобы разобрать их. Для выполнения регулярных выражений в Objective-C, проверьте RegexKit.Edit:Как указывает @Nathan, использование NSScanner-это гораздо более простой способ проанализировать все числа из строки. Я совершенно не знал об этом варианте,так что подпиши его за предложение. (Мне даже не нравится использовать регулярное выражение, поэтому я предпочитаю подходы для этого они не нужны.)

Если вы хотите отформатировать номера телефонов для отображения, стоит взглянуть на NSNumberFormatter. Я предлагаю вам прочитать это связано так вопрос и этот учебник для iPhone для советов по этому поводу. Помните, что номера телефонов отформатированы по-разному в зависимости от местоположения и/или язык.

Хм. Первый ответ кажется мне совершенно неправильным. NSScanner действительно предназначен для разбора. В отличие от регулярных выражений, в нем вы разбираете строку по одному крошечному куску за раз. Вы инициализируете его строкой, и он поддерживает индекс того, как далеко он получил строку; этот индекс всегда является его опорной точкой, и любые команды, которые вы ему даете, относятся к этой точке. Вы говорите ему: "хорошо, дайте мне следующий кусок символов в этом наборе" или "дайте мне целое число, которое вы найдете в строке", и те начните с текущего индекса и двигайтесь вперед, пока они не найдут что-то, что не соответствует. Если самый первый символ уже не соответствует, то метод возвращает NO,и индекс не увеличивается.

код в первом примере сканируется" (123)456-7890 " для десятичных символов, который уже не выполняется с самого первого символа, поэтому вызов scanCharactersFromSet: intoString: оставляет переданную строку strippedString в покое и возвращает NO; код полностью игнорирует проверку возвращаемое значение, оставляя строку strippedString неназначенной. Даже если первый символ был цифрой, этот код потерпит неудачу, так как он будет возвращать только цифры, которые он находит до первого тире или paren или что-то еще.

Если вы действительно хотите использовать NSScanner, вы можете поместить что-то подобное в цикл и продолжать проверять отсутствие возвращаемого значения, и если вы получите это, вы можете увеличить 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, чтобы упростить эту общую операцию.

NSString+AllowCharactersInSet.h

@interface NSString (AllowCharactersInSet)

- (NSString *)stringByAllowingOnlyCharactersInSet:(NSCharacterSet *)characterSet;

@end

NSString+AllowCharactersInSet.м

@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)

swift 4.1

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

на основе ответа Джона Фогеля здесь это как расширение 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];

];

держите его просто!

Comments

    Ничего не найдено.