62

I want to ask a question about the NSString * in objective C. Can I check the last char of a NSString * object?

Example:

NSString* data = @"abcde,";

if(data is end with ',') // I don't know this part
  // do sth
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Questions
  • 20,055
  • 29
  • 72
  • 101

3 Answers3

170
NSString *data = @"abcde,";
if([data hasSuffix:@","]) // This returns true in this example
    // do something
  • robinjam, thank you for your reply. I try it, but it did not work. Is it another method? – Questions Jul 14 '10 at 10:12
  • robinjam, thank you for your reply. And I try another NSString *, it works also. I guess it is some other problems of my program. Because the NSString * is passed from other object, can I display the last char of the NSString as I want to confirm that the last char. Thank you. – Questions Jul 15 '10 at 01:07
  • 12
    Try this: `NSString *lastCharacter = [myString substringFromIndex:[myString length] - 1]; NSLog(@"%@", lastCharacter);` –  Jul 15 '10 at 03:41
6

The NSString Programming Guide recommends:

If you simply want to determine whether a string contains a given pattern, you can use a predicate:

So, in your example:

NSString *data = @"abcde,";

// Create the predicate
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"SELF endswith %@", @","];

// Run the predicate
// match == YES if the predicate is successful
BOOL match = [myPredicate evaluateWithObject:data];

// Do what you want
if (match) {
    // do something
}

A bit long winded to write? Maybe, but if you do this in more than one place it can be easily refactored into a helper method.

Here's a link to the NSPredicate docs.

Edit

I've done some profiling and it is overkill in this simple case (see my comment below). I'll leave the answer up here anyway just as an example of using predicates for this sort of thing.

Abizern
  • 146,289
  • 39
  • 203
  • 257
  • 7
    Woah! Predicate evaluation just to check the suffix of a string? It's a bit overkill. – dreamlax Jul 14 '10 at 14:02
  • Why is it overkill? `-hasSuffix:` is just a convenience method for setting up a search on the NSString. Just because it's shorter to write does not make it more efficient. Also it's a recommendation from the docs (as I linked to) and it also gives the questioner another option for testing his code as the `-hasSuffix:` approach isn't working, and introduces a new approach to string searching that the questioner and others may not have previously considered. – Abizern Jul 14 '10 at 14:16
  • 1
    It is overkill because you have to create a predicate object, which has to parse the predicate format string, and also you have to evaluate the predicate object with the target object. `hasSuffix:` only has to ensure that the last characters of the receiver are equal to the argument. It wouldn't surprise me if the predicate `endswith` just used `hasSuffix:` internally. Also, the code provided for `hasSuffix:` in the other answer works. If it is not working for the OP then he has not given us enough information to correctly answer his question. – dreamlax Jul 14 '10 at 14:21
  • 2
    @dreamlax. You know; you're right. I did some profiling and the NSPredicate method is about 3 times slower than using `-hasSuffix`. 36ms compared to 14ms to scan 107,000 words (so it's still fast). I stand corrected! – Abizern Jul 16 '10 at 04:34
  • I would be curious to see how the new regex API performs in comparison. I bet it would be slower but who knows. – Marcus S. Zarra Jul 16 '10 at 15:41
  • Never regex if you can avoid it. The very definition of the regex semantics enforces inefficient algorithm, and it imposes an "unknown time" on any evaluation - depending on the input contents. NSExpression is much faster even in its slower forms, and if you implement it with your own code-blocks it may perform really good. – Motti Shneor Jun 27 '23 at 10:38
5

If you're worried about performance, and you want to check for one character, using -characterAtIndex: method may well be faster. -hasSuffix: takes a string, so potentially needs to do more work than just checking a single character (though the difference may be trivial).

You can also use categories to add a method to NSString like this:

@interface NSString(StringUtilities)
    - (BOOL) endsWithCharacter: (unichar) c;
@end

@implementation NSString(StringUtilities)

    - (BOOL) endsWithCharacter: (unichar) c
    {
        NSUInteger length = [self length];
        return (length > 0) && ([self characterAtIndex: length - 1] == c);
    }

@end

// test it...
NSString *data = @"abcd,";
if ([data endsWithCharacter: L','])
{

}

You should profile, of course, to be sure. Bear in mind though that by putting endsWithCharacter into a method we've added the message passing overhead to it, which will skew the profiling results unless you do the same when profiling the alternatives.

All of this is probably premature optimisation for most cases - but of course if you're doing this test thousands of times a second it may well matter (in that case you would probably want to use the code directly in the loop, as message passing inside a tight inner loop isn't a great plan).

Sam Deane
  • 1,553
  • 1
  • 13
  • 17