2010-04-03 2 views

Répondre

11

Pour tester qu'une chaîne se termine par des chiffres, vous pouvez utiliser un NSPredicate, comme:

NSPredicate endsNumerically = [NSPredicate predicateWithFormat:@"SELF matches %@", @"\\d+$"]; 
[endsNumerically evaluateWithObject:string]; // returns TRUE if predicate succeeds 

NSScanner est parfois utile pour extraire les choses à partir de chaînes, mais il ne scanne pas en arrière. Vous pouvez définir une classe Gnirts (reverse string) et l'utiliser avec un NSScanner, mais c'est sans doute plus compliqué que ça en vaut la peine.

NSString de rangeOfCharacterFromSet:options:, que j'avais l'espoir d'utiliser, ne regarde que pour un seul caractère (il est comme strchr and strrchr, si vous êtes familier avec C), mais nous pouvons rouler notre propre qui retourne une plage contiguë de caractères à partir d'un ensemble (un peu comme strspn) en tant que category sur NSString. Pendant que nous y sommes, incluons des méthodes qui renvoient des sous-chaînes plutôt que des plages.

RangeOfCharacters.h:

@interface NSString (RangeOfCharacters) 
/* note "Characters" is plural in the methods. It has poor readability, hard to 
* distinguish from the rangeOfCharacterFromSet: methods, but it's standard Apple 
* convention. 
*/ 
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet; 
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask; 
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range; 

// like the above, but return a string rather than a range 
-(NSString*)substringFromSet:(NSCharacterSet*)aSet; 
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask; 
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range; 
@end 

RangeOfCharacters.m:

@implementation NSString (RangeOfCharacters) 
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet { 
    return [self rangeOfCharactersFromSet:aSet options:0]; 
} 

-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask { 
    NSRange range = {0,[self length]}; 
    return [self rangeOfCharactersFromSet:aSet options:mask range:range]; 
} 

-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range { 
    NSInteger start, curr, end, step=1; 
    if (mask & NSBackwardsSearch) { 
     step = -1; 
     start = range.location + range.length - 1; 
     end = range.location-1; 
    } else { 
     start = range.location; 
     end = start + range.length; 
    } 
    if (!(mask & NSAnchoredSearch)) { 
     // find first character in set 
     for (;start != end; start += step) { 
      if ([aSet characterIsMember:[self characterAtIndex:start]]) { 
#ifdef NOGOTO 
       break; 
#else 
       // Yeah, a goto. If you don't like them, define NOGOTO. 
       // Method will work the same, it will just make unneeded 
       // test whether character at start is in aSet 
       goto FoundMember; 
#endif 
      } 
     } 
#ifndef NOGOTO 
     goto NoSuchMember; 
#endif 
    } 
    if (![aSet characterIsMember:[self characterAtIndex:start]]) { 
    NoSuchMember: 
     // no characters found within given range 
     range.location = NSNotFound; 
     range.length = 0; 
     return range; 
    } 

FoundMember: 
    for (curr = start; curr != end; curr += step) { 
     if (![aSet characterIsMember:[self characterAtIndex:curr]]) { 
      break; 
     } 
    } 
    if (curr < start) { 
     // search was backwards 
     range.location = curr+1; 
     range.length = start - curr; 
    } else { 
     range.location = start; 
     range.length = curr - start; 
    } 
    return range; 
} 

-(NSString*)substringFromSet:(NSCharacterSet*)aSet { 
    return [self substringFromSet:aSet options:0]; 
} 

-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask { 
    NSRange range = {0,[self length]}; 
    return [self substringFromSet:aSet options:mask range:range]; 
} 
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range { 
    NSRange range = [self rangeOfCharactersFromSet:aSet options:mask range:range]; 
    if (NSNotFound == range.location) { 
     return nil; 
    } 
    return [self substringWithRange:range]; 
} 
@end 

Pour utiliser la nouvelle catégorie pour vérifier qu'une chaîne se termine par des chiffres ou pour extraire le nombre:

NSString* number = [string substringFromSet:[NSCharacterSet decimalDigitCharacterSet] 
          options:NSBackwardsSearch|NSAnchoredSearch]; 
if (number != nil) { 
    return [number intValue]; 
} else { 
    // string doesn't end with a number. 
} 

Enfin, vous pouvez utiliser une bibliothèque d'expressions régulières tierce, telle que RegexKit ou RegexkitLite.

+0

Merci d'avoir répondu. Je pense qu'il y a deux fautes de frappe dans votre deuxième extrait. range devrait être digitRange et le == devrait être! = right? En outre, le deuxième extrait trouve 2 pour la valeur 12. Je voudrais trouver tous les nombres positifs ne concernant pas leur nombre de chiffres. Est-ce possible avec votre deuxième extrait ou devrais-je utiliser les bibliothèques regex? –

+0

@Michael: oui. À l'origine, j'avais d'abord la branche «chaîne ne se termine pas par un numéro»; apparemment, j'ai négligé d'inverser le test. Je vais mettre à jour ma réponse avec un extrait qui extrait le nombre entier pour de vrai une fois que je me suis reposé. – outis

+0

Merci de vérifier pour moi. –

Questions connexes