Количество вхождений символа в NSString

Шаблоны должны использоваться в заголовках, потому что компилятор должен создавать экземпляры разных версий кода в зависимости от параметров, заданных / выведенных для параметров шаблона. Помните, что шаблон не представляет собой код напрямую, а шаблон для нескольких версий этого кода. Когда вы компилируете функцию non-template в файле .cpp, вы компилируете конкретную функцию / класс. Это не относится к шаблонам, которые могут быть созданы с использованием разных типов, а именно, если при замене параметров шаблона конкретными типами необходимо исправить конкретный код.

Была функция с ключевым словом export, которая была предназначенный для отдельной компиляции. Функция export устарела в C++11 и, AFAIK, только один компилятор реализовал ее. Вы не должны использовать export. Отдельная компиляция невозможна в C++ или C++11, но, возможно, в C++17, если понятия в нее входят, мы могли бы иметь некоторый способ отдельной компиляции.

Для отдельной компиляции, которая должна быть достигнута, разделить проверка шаблона тела должна быть возможна. Кажется, что решение возможно с концепциями. Взгляните на этот документ , недавно представленный на совещании по стандартам. Я думаю, что это не единственное требование, поскольку вам все равно необходимо создать код кода шаблона в коде пользователя.

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

35
задан Josh Caswell 28 September 2014 в 18:37
поделиться

6 ответов

replaceOccurrencesOfString: withString : options: range: вернет количество символов, замененных в NSMutableString .

[string replaceOccurrencesOfString:@"A" 
                        withString:@"B" 
                           options:NSLiteralSearch 
                             range:NSMakeRange(0, [receiver length])];
16
ответ дан 27 November 2019 в 05:08
поделиться

Сравнение производительности для различных решений Objective C.

Предполагают, что все методы ниже являются расширениями NSString (в @implementation NSString (CountOfOccurrences)).

Как образец, я использовал случайную сгенерированную строку длины 100 000 000 использований всех латинских символов (CharacterSet(charactersIn: "\u{0020}"..."\u{036F}") в Swift). И символ для подсчета был @"a".

Тесты, выполненные на Xcode 10.3 на Средстве моделирования в конфигурации выпуска.

Быстрые решения (точная познаковая эквивалентность)

существует два способа значить символ: использование NSLiteralSearch или нет. Количество будет отличаться, и производительность будет существенно затронута. Для самых быстрых результатов мы выполним точную познаковую эквивалентность. Ниже четырех решений дают очень близкие результаты проверки производительности.

1. Быстрое решение: адаптация ответа CynicismRising.

Используя [1 122] replaceOccurrencesOfString:withString:options:range: . Это - быстрое решение во всех сценариях: даже если Вы заменяете NSLiteralSearch [1 112], Вы еще быстрее, чем pierrot3887 решение для сканера.

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    return [[NSMutableString stringWithString:self] replaceOccurrencesOfString:stringToFind
                                                                    withString:stringToFind
                                                                       options:NSLiteralSearch
                                                                         range:NSMakeRange(0, self.length)];
}

2. Второй самый быстрый, отвечает другая адаптация CynicismRising.

Используя [1 123] stringByReplacingOccurrencesOfString:withString:options:range: .

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    NSString *strippedString = [self stringByReplacingOccurrencesOfString:stringToFind
                                                               withString:@""
                                                                  options:NSLiteralSearch
                                                                    range:NSMakeRange(0, self.length)];
    return (self.length - strippedString.length) / stringToFind.length;
}

3. Третий самый быстрый, решение Jacque.

Используя [1 124] CFStringGetCharacterFromInlineBuffer . См. https://stackoverflow.com/a/15947190/1033581.

4. Четвертый самый быстрый, преобразование [1 126] мой ответ Swift к Objective C.

Используя [1 127] rangeOfString:options:range: .

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    //assert(stringToFind.length);
    NSUInteger count = 0;
    NSRange searchRange = NSMakeRange(0, self.length);
    NSRange foundRange;
    while ((void)(foundRange = [self rangeOfString:stringToFind options:NSLiteralSearch range:searchRange]), foundRange.length) {
        count += 1;
        NSUInteger loc = NSMaxRange(foundRange);
        searchRange = NSMakeRange(loc, self.length - loc);
    }
    return count;
}

Медленные решения

ниже решений не используют NSLiteralSearch и не выполняют точную познаковую эквивалентность. Первые два, возможно, в 10 раз медленнее, чем быстрые решения, и последний, возможно, в 100 раз медленнее.

5. Медленное решение: адаптация ответа pierrot3887

Используя [1 128] scanUpToString:intoString: . Слишком плохо то, что NSScanner не предлагает опции для точной познаковой эквивалентности.

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    NSScanner *scanner = [NSScanner scannerWithString:self];
    scanner.charactersToBeSkipped = nil;
    scanner.caseSensitive = YES;
    NSUInteger numberOfOccurrences = 0;
    while (!scanner.isAtEnd) {
        [scanner scanUpToString:stringToFind intoString:nil];
        if (!scanner.isAtEnd) {
            numberOfOccurrences++;
            [scanner scanString:stringToFind intoString:nil];
        }
    }
    return numberOfOccurrences;
}

6. Более медленное решение: решение

для gbaor Используя [1 129] componentsSeparatedByString: . Относительно аргумента выполнимых в одной строке обратите внимание, что быстрое решение, данное выше, является также одним лайнером.

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    return [self componentsSeparatedByString:stringToFind].count - 1;
}

7. Самое медленное решение: адаптация ответа vikingosegundo

Используя [1 130] enumerateSubstringsInRange:options:usingBlock: .

- (NSUInteger)countOccurrencesOfCharacter:(NSString *)characterToFind
{
    __block NSUInteger counter = 0;
    [self enumerateSubstringsInRange:NSMakeRange(0, self.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        if ([characterToFind isEqualToString:substring]) counter += 1;
    }];
    return counter;
}
1
ответ дан 27 November 2019 в 05:08
поделиться

Я бы, вероятно, использовал

NSString rangeOfCharacterFromSet:

или

rangeOfCharacterFromSet: options: range ::

, где набор - это набор символов, которые вы ищете . Он возвращается с местоположением первого символа, соответствующего набору. Сохраните массив или словарь и увеличьте счетчик символов, затем повторите.

1
ответ дан 27 November 2019 в 05:08
поделиться

Когда вы ищете что-то в NSString , попробуйте сначала использовать NSScanner .

NSString *yourString = @"ABCCDEDRFFED"; // For example
NSScanner *scanner = [NSScanner scannerWithString:yourString];

NSCharacterSet *charactersToCount = [NSCharacterSet characterSetWithCharactersInString:@"C"]; // For example
NSString *charactersFromString;

if (!([scanner scanCharactersFromSet:charactersToCount 
                          intoString:&charactersFromString])) {
    // No characters found
    NSLog(@"No characters found");
}

// should return 2 for this
NSInteger characterCount = [charactersFromString length];
7
ответ дан 27 November 2019 в 05:08
поделиться

Пример с сканером разбился на iPhone. Я нашел это решение:

NSString *yourString = @"ABCCDEDRFFED"; // For example
NSScanner *mainScanner = [NSScanner scannerWithString:yourString];
NSString *temp;
NSInteger numberOfChar=0;
while(![mainScanner isAtEnd])
{
   [mainScanner scanUpToString:@"C" intoString:&temp];
   numberOfChar++;
   [mainScanner scanString:@"C" intoString:nil];
}

Это работало для меня без аварии. Надеюсь, это может помочь!

1
ответ дан 27 November 2019 в 05:08
поделиться

Ваше решение не сработало для меня, я добавил условие в цикле для приращения числа OfChar только в том случае, если mainScanner достиг конца строки :

NSString *yourString = @"ABCCDEDRFFED"; // For example
NSScanner *mainScanner = [NSScanner scannerWithString:yourString];
NSString *temp;
NSInteger numberOfChar=0;
while(![mainScanner isAtEnd])
{
   [mainScanner scanUpToString:@"C" intoString:&temp];
   if(![mainScanner isAtEnd]) {
      numberOfChar++;
      [mainScanner scanString:@"C" intoString:nil];
   }
}

Обратите внимание, что это быстрое исправление, у меня нет времени сделать элегантное решение...

2
ответ дан 27 November 2019 в 05:08
поделиться