Numero di occorrenze di un carattere in una NSString?

Come posso ottenere il numero di volte in cui una NSString (per esempio, @"cake") viene visualizzato in un grande NSString (per esempio, @"Cheesecake, apple cake, and cherry pie")?

Ho bisogno di fare questo su un sacco di stringhe, in modo qualunque sia il metodo che uso avrebbe bisogno di essere relativamente veloce.

Grazie!

InformationsquelleAutor igul222 | 2010-01-30

 

13 Replies
  1. 98

    Questo non è testato, ma dovrebbe essere un buon inizio.

    NSUInteger count = 0, length = [str length];
    NSRange range = NSMakeRange(0, length); 
    while(range.location != NSNotFound)
    {
      range = [str rangeOfString: @"cake" options:0 range:range];
      if(range.location != NSNotFound)
      {
        range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
        count++; 
      }
    }
    • È len = length?
    • sì, grazie. Ho risolto ora.
    • gamma = [str rangeOfString: @”torta” opzioni:0 range:intervallo); LOC Questo deve essere sostituito dal seguente: gamma = [str rangeOfString: @”torta” opzioni:0 range:intervallo]; La parentesi utilizzato invece di staffa.
    • Grazie, @Guru, fissa di nuovo.
    • sei il benvenuto. 🙂
  2. 70

    Una regex come quello qui sotto, dovrebbe fare il lavoro senza un ciclo di interazione…

    A cura

    NSString *string = @"Lots of cakes, with a piece of cake.";
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"cake" options:NSRegularExpressionCaseInsensitive error:&error];
    NSUInteger numberOfMatches = [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])];
    NSLog(@"Found %i",numberOfMatches);

    Disponibile solo su iOS 4.x e superiori.

    • [stringa di lunghezza] dovrebbe essere [testodacercare lunghezza] penso?
    • Grazie @Joris, modificato e corretto.
    • Questo è un ottimo modo per fare questo.
    • Risposta impressionante.. Grazie Mate..+1
    • Questo dovrebbe essere accettato risposta. Onestamente, questo è molto meglio per la cat. Utilizzare le espressioni regolari se avete bisogno di più che solo la prima o l’ultima occorrenza di una stringa.
    • Anche se questa implementazione è più compatto, ha accettato di rispondere utilizzando un NSRange loop viene eseguito più velocemente. In un rapido test in un documento di testo con 30 pagine il ciclo di ricerca per una singola parola ha preso 9ms, mentre l’espressione regolare attuazione preso 60ms.
    • loop tempo di ricerca aumenterà per ogni occorrenza che si hanno, regex non..
    • potrebbe per favore postare un link a un documento di testo
    • basta prendere un qualsiasi documento di testo, ad esempio un articolo scientifico e di eseguire algoritmi di ricerca
    • anche motore RegEx opere di iterazione e di backtracking, internamente. Non so perché pensi che regex il tempo di elaborazione non aumentare di dimensioni più grandi, oggetto di testo. Provare qualsiasi documento in regex101.com/#pcre e si potrebbe trovare come il numero di passaggi iterativi aumentare con l’aumento della quantità di testo. IMHO, per qualsiasi prestazione operazione critica regex non è mai una buona scelta.

  3. 43

    è alla ricerca di un metodo migliore, poi la mia, ma ecco un altro esempio:

    NSString *find = @"cake";
    NSString *text = @"Cheesecake, apple cake, and cherry pie";
    
    NSInteger strCount = [text length] - [[text stringByReplacingOccurrencesOfString:find withString:@""] length];
    strCount /= [find length];

    Vorrei sapere quale è più efficace.

    E ho fatto un NSString categoria per il miglior utilizzo:

    //NSString+CountString.m
    
    @interface NSString (CountString)
    - (NSInteger)countOccurencesOfString:(NSString*)searchString;
    @end
    
    @implementation NSString (CountString)
    - (NSInteger)countOccurencesOfString:(NSString*)searchString {
        NSInteger strCount = [self length] - [[self stringByReplacingOccurrencesOfString:searchString withString:@""] length];
        return strCount / [searchString length];
    }
    @end

    semplicemente chiamare da:

    [text countOccurencesOfString:find];

    Opzionale:
    è possibile modificare la ricerca case insensitive definendo options:

    • Mi piace questo approccio, questo dovrebbe essere accettato risposta.
    • Più sottovalutati della risposta;
  4. 23

    Ci sono un paio di modi per farlo. Si potrebbe, in modo iterativo, chiamata rangeOfString:options:range:, o si potrebbe fare qualcosa di simile:

    NSArray * portions = [aString componentsSeparatedByString:@"cake"];
    NSUInteger cakeCount = [portions count] - 1;

    MODIFICA stavo pensando a questa domanda e ho scritto un lineare algoritmo in tempo per fare la ricerca (lineare, per la lunghezza di un array in una stringa):

    + (NSUInteger) numberOfOccurrencesOfString:(NSString *)needle inString:(NSString *)haystack {
        const char * rawNeedle = [needle UTF8String];
        NSUInteger needleLength = strlen(rawNeedle);
    
        const char * rawHaystack = [haystack UTF8String];
        NSUInteger haystackLength = strlen(rawHaystack);
    
        NSUInteger needleCount = 0;
        NSUInteger needleIndex = 0;
        for (NSUInteger index = 0; index < haystackLength; ++index) {
            const char thisCharacter = rawHaystack[index];
            if (thisCharacter != rawNeedle[needleIndex]) {
                needleIndex = 0; //they don't match; reset the needle index
            }
    
            //resetting the needle might be the beginning of another match
            if (thisCharacter == rawNeedle[needleIndex]) {
                needleIndex++; //char match
                if (needleIndex >= needleLength) {
                    needleCount++; //we completed finding the needle
                    needleIndex = 0;
                }
            }
        }
    
        return needleCount;
    }
    • Il componentsSeparatedByString soluzione provoca un sacco di inutili allocazione di memoria.
    • vero, ma è un due-linea di soluzione.
    • mi piace, ottima soluzione.
    • numberOfOccurrencesOfString:inString: non riesce quando la stringa di ricerca inizia con gli stessi caratteri come l’ago, ma poi non corrisponde più, pur essendo all’interno di una corrispondenza corretta. Questo perché needleIndex è sempre stato resettato a 0, quando in realtà richiede una logica più complessa. Prendiamo un semplice esempio: [self numberOfOccurrencesOfString:@"aab" inString:@"aaab"] il valore di ritorno è 0, quando si dovrebbe chiaramente essere 1.
    • Vedi la Boyer-Moore e di Knuth-Morris-Pratt algoritmi per tutte le complessità coinvolti in un efficiente sottostringa algoritmo di matching.
  5. 11

    Un più rapido tipo, ma probabilmente meno efficiente soluzione.

    - (int)numberOfOccurencesOfSubstring:(NSString *)substring inString:(NSString*)string
    {
        NSArray *components = [string componentsSeparatedByString:substring];
        return components.count-1; //Two substring will create 3 separated strings in the array.
    }
    • Per “componenti.count-1;”
    • Sappiamo che questo è meno efficiente?
  6. 3

    Qui è una versione fatta come un’estensione NSString (stessa idea di Matteo Flaschen risposta):

    @interface NSString (my_substr_search)
    - (unsigned) countOccurencesOf: (NSString *)subString;
    @end
    @implementation NSString (my_substring_search)
    - (unsigned) countOccurencesOf: (NSString *)subString {
        unsigned count = 0;
        unsigned myLength = [self length];
        NSRange uncheckedRange = NSMakeRange(0, myLength);
        for(;;) {
            NSRange foundAtRange = [self rangeOfString:subString
                                               options:0
                                                 range:uncheckedRange];
            if (foundAtRange.location == NSNotFound) return count;
            unsigned newLocation = NSMaxRange(foundAtRange); 
            uncheckedRange = NSMakeRange(newLocation, myLength-newLocation);
            count++;
        }
    }
    @end
    <somewhere> {
        NSString *haystack = @"Cheesecake, apple cake, and cherry pie";
        NSString *needle = @"cake";
        unsigned count = [haystack countOccurencesOf: needle];
        NSLog(@"found %u time%@", count, count == 1 ? @"" : @"s");
    }
  7. 3

    Ecco un’altra versione come una categoria a NSString:

    -(NSUInteger) countOccurrencesOfSubstring:(NSString *) substring {
        if ([self length] == 0 || [substring length] == 0)
            return 0;
    
        NSInteger result = -1;
        NSRange range = NSMakeRange(0, 0);
        do {
            ++result;
            range = NSMakeRange(range.location + range.length,
                                self.length - (range.location + range.length));
            range = [self rangeOfString:substring options:0 range:range];
        } while (range.location != NSNotFound);
        return result;
    }
  8. 3

    Swift soluzione sarebbe:

    var numberOfSubstringAppearance = 0
    let length = count(text)
    var range: Range? = Range(start: text.startIndex, end: advance(text.startIndex, length))
    
    while range != nil {
    
        range = text.rangeOfString(substring, options: NSStringCompareOptions.allZeros, range: range, locale: nil)
    
        if let rangeUnwrapped = range {
    
            let remainingLength = length - distance(text.startIndex, rangeUnwrapped.endIndex)
            range = Range(start: rangeUnwrapped.endIndex, end: advance(rangeUnwrapped.endIndex, remainingLength))
            numberOfSubstringAppearance++
         }
    }
    • Traduzione di swift, ma per favore, modifica la tua risposta per aggiungere Swift 3 soluzione.
  9. 1

    Matteo Flaschen la risposta è stato un buon inizio per me. Qui è quello che ho finito per usare la forma di un metodo. Ho preso un approccio leggermente diverso per il ciclo. Questo è stato testato con le stringhe vuote passate a stringToCount e di testo e con il stringToCount che si verificano come il primo e/o ultimo carattere del testo.

    Io uso questo metodo regolarmente a contare i paragrafi in passato di testo (ie. stringToCount = @”\r”).

    Spero che questo per qualcun’.

        - (int)countString:(NSString *)stringToCount inText:(NSString *)text{
            int foundCount=0;
            NSRange range = NSMakeRange(0, text.length);
            range = [text rangeOfString:stringToCount options:NSCaseInsensitiveSearch range:range locale:nil];
            while (range.location != NSNotFound) {
                foundCount++;
                range = NSMakeRange(range.location+range.length, text.length-(range.location+range.length));
                range = [text rangeOfString:stringToCount options:NSCaseInsensitiveSearch range:range locale:nil];
            }
    
            return foundCount;
       }

    Chiamata di esempio supponendo che il metodo è in una classe di nome myHelperClass…

    int foundCount = [myHelperClass countString:@"n" inText:@"Now is the time for all good men to come to the aid of their country"];
  10. 0
    for(int i =0;i<htmlsource1.length-search.length;i++){
      range = NSMakeRange(i,search.length);
      checker = [htmlsource1 substringWithRange:range];
    
      if ([search isEqualToString:checker]) {
       count++;
    
      }
    
     }
  11. 0

    Built-in metodo. Vorrei suggerire di restituzione di un c-string e l’utilizzo di un comune c-string stile algoritmo per la sottostringa di conteggio… se hai davvero bisogno di questo per essere veloce.

    Se si vuole rimanere in Objective C, questo link potrebbe aiutare. Descrive le principali sottostringa di ricerca per NSString. Se si lavora con le gamme, regolare e conte, allora avrai un “puro” Obiettivo C soluzione… anche se lenta.

    • Non chiamare ad esempio NSString.UTF8String causa di una nuova stringa allocata? Sembra che sarebbe più veloce per utilizzare NSString metodi, come rangeOfString.
    • Sì, lo fa. Due volte, se si decide di copiare per un uso successivo. La creazione di un c-string dopo e in cerca di k sottostringhe minimo impatto, rispetto per approfondire NSString metodi e l’assegnazione di una sottostringa dopo ogni colpo.
    • Non necessariamente. Se si inizia con un immutabile stringa, sottostringhe non richiedono stanziamenti. Così come Chris dimostra, inoltre, non è necessario per estrarre sottostringhe a tutti. Nota anche che la conversione di una stringa in UTF8 può essere estremamente costoso se la stringa è, diciamo, UTF-16.
  12. 0
    -(IBAction)search:(id)sender{
    
      int  maincount = 0;
        for (int i=0; i<[self.txtfmainStr.text length]; i++) {
            char c =[self.substr.text characterAtIndex:0];
            char cMain =[self.txtfmainStr.text characterAtIndex:i];
            if (c == cMain) {
              int  k=i;
                int count=0;
                for (int j = 0; j<[self.substr.text length]; j++) {
    
                    if (k ==[self.txtfmainStr.text length]) {
                        break;
                    }
    
                    if ([self.txtfmainStr.text characterAtIndex:k]==[self.substr.text characterAtIndex:j]) {
    
                        count++;
                    }                
    
                    if (count==[self.substr.text length]) {
                        maincount++;
                    }
    
                    k++;
                }
    
    
            }
    
            NSLog(@"%d",maincount);
        }
    
    }

Lascia un commento