Check if last characters of an NSString are numbers











up vote
0
down vote

favorite












Is it possible to see of a string ends with a number which length is not known?




  1. "String 1" -> 1

  2. "String 4356" -> 4356

  3. "String" -> nil


If so, how can I determine that number?










share|improve this question


























    up vote
    0
    down vote

    favorite












    Is it possible to see of a string ends with a number which length is not known?




    1. "String 1" -> 1

    2. "String 4356" -> 4356

    3. "String" -> nil


    If so, how can I determine that number?










    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      Is it possible to see of a string ends with a number which length is not known?




      1. "String 1" -> 1

      2. "String 4356" -> 4356

      3. "String" -> nil


      If so, how can I determine that number?










      share|improve this question













      Is it possible to see of a string ends with a number which length is not known?




      1. "String 1" -> 1

      2. "String 4356" -> 4356

      3. "String" -> nil


      If so, how can I determine that number?







      cocoa nsstring numbers






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Apr 3 '10 at 9:57









      Michael Matheus

      3417




      3417
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          11
          down vote



          accepted










          To test that a string ends with numbers, you can use an NSPredicate, such as:



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


          NSScanner is sometimes useful for extracting things from strings, but it doesn't scan backward. You could define a Gnirts (reverse string) class and use that with an NSScanner, but that's probably more hassle than it's worth.



          NSString's rangeOfCharacterFromSet:options:, which I had hope to use, only looks for a single character (it's like strchr and strrchr, if you're familiar with C), but we can roll our own that returns a contiguous range of characters from a set (a little like strspn) as a category on NSString. While we're at it, let's include methods that return substrings rather than ranges.



          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


          To use the new category to check that a string ends with digits or to extract the number:



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


          Lastly, you can use a third party regular expression library, such as RegexKit or RegexkitLite.






          share|improve this answer























          • Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
            – Michael Matheus
            Apr 3 '10 at 11:59










          • @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
            – outis
            Apr 3 '10 at 13:14










          • Thanks for checking it out for me.
            – Michael Matheus
            Apr 3 '10 at 14:04










          • Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
            – Michael Matheus
            Apr 4 '10 at 7:05










          • +1 for the awesomeness of using goto AND making the code work without it
            – Akku
            Feb 22 '11 at 13:49


















          up vote
          0
          down vote













          I couldn't get the NSPredicate code above to work correctly, though it looks like it should. Instead I accomplished the same thing with



          if ([string rangeOfString:@"\d+$" options:NSRegularExpressionSearch].location != NSNotFound) {
          // string ends with a number
          }


          Hat-tip to this answer.






          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2570853%2fcheck-if-last-characters-of-an-nsstring-are-numbers%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            11
            down vote



            accepted










            To test that a string ends with numbers, you can use an NSPredicate, such as:



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


            NSScanner is sometimes useful for extracting things from strings, but it doesn't scan backward. You could define a Gnirts (reverse string) class and use that with an NSScanner, but that's probably more hassle than it's worth.



            NSString's rangeOfCharacterFromSet:options:, which I had hope to use, only looks for a single character (it's like strchr and strrchr, if you're familiar with C), but we can roll our own that returns a contiguous range of characters from a set (a little like strspn) as a category on NSString. While we're at it, let's include methods that return substrings rather than ranges.



            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


            To use the new category to check that a string ends with digits or to extract the number:



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


            Lastly, you can use a third party regular expression library, such as RegexKit or RegexkitLite.






            share|improve this answer























            • Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
              – Michael Matheus
              Apr 3 '10 at 11:59










            • @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
              – outis
              Apr 3 '10 at 13:14










            • Thanks for checking it out for me.
              – Michael Matheus
              Apr 3 '10 at 14:04










            • Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
              – Michael Matheus
              Apr 4 '10 at 7:05










            • +1 for the awesomeness of using goto AND making the code work without it
              – Akku
              Feb 22 '11 at 13:49















            up vote
            11
            down vote



            accepted










            To test that a string ends with numbers, you can use an NSPredicate, such as:



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


            NSScanner is sometimes useful for extracting things from strings, but it doesn't scan backward. You could define a Gnirts (reverse string) class and use that with an NSScanner, but that's probably more hassle than it's worth.



            NSString's rangeOfCharacterFromSet:options:, which I had hope to use, only looks for a single character (it's like strchr and strrchr, if you're familiar with C), but we can roll our own that returns a contiguous range of characters from a set (a little like strspn) as a category on NSString. While we're at it, let's include methods that return substrings rather than ranges.



            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


            To use the new category to check that a string ends with digits or to extract the number:



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


            Lastly, you can use a third party regular expression library, such as RegexKit or RegexkitLite.






            share|improve this answer























            • Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
              – Michael Matheus
              Apr 3 '10 at 11:59










            • @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
              – outis
              Apr 3 '10 at 13:14










            • Thanks for checking it out for me.
              – Michael Matheus
              Apr 3 '10 at 14:04










            • Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
              – Michael Matheus
              Apr 4 '10 at 7:05










            • +1 for the awesomeness of using goto AND making the code work without it
              – Akku
              Feb 22 '11 at 13:49













            up vote
            11
            down vote



            accepted







            up vote
            11
            down vote



            accepted






            To test that a string ends with numbers, you can use an NSPredicate, such as:



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


            NSScanner is sometimes useful for extracting things from strings, but it doesn't scan backward. You could define a Gnirts (reverse string) class and use that with an NSScanner, but that's probably more hassle than it's worth.



            NSString's rangeOfCharacterFromSet:options:, which I had hope to use, only looks for a single character (it's like strchr and strrchr, if you're familiar with C), but we can roll our own that returns a contiguous range of characters from a set (a little like strspn) as a category on NSString. While we're at it, let's include methods that return substrings rather than ranges.



            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


            To use the new category to check that a string ends with digits or to extract the number:



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


            Lastly, you can use a third party regular expression library, such as RegexKit or RegexkitLite.






            share|improve this answer














            To test that a string ends with numbers, you can use an NSPredicate, such as:



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


            NSScanner is sometimes useful for extracting things from strings, but it doesn't scan backward. You could define a Gnirts (reverse string) class and use that with an NSScanner, but that's probably more hassle than it's worth.



            NSString's rangeOfCharacterFromSet:options:, which I had hope to use, only looks for a single character (it's like strchr and strrchr, if you're familiar with C), but we can roll our own that returns a contiguous range of characters from a set (a little like strspn) as a category on NSString. While we're at it, let's include methods that return substrings rather than ranges.



            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


            To use the new category to check that a string ends with digits or to extract the number:



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


            Lastly, you can use a third party regular expression library, such as RegexKit or RegexkitLite.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 4 '10 at 2:18

























            answered Apr 3 '10 at 10:31









            outis

            58.2k13114173




            58.2k13114173












            • Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
              – Michael Matheus
              Apr 3 '10 at 11:59










            • @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
              – outis
              Apr 3 '10 at 13:14










            • Thanks for checking it out for me.
              – Michael Matheus
              Apr 3 '10 at 14:04










            • Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
              – Michael Matheus
              Apr 4 '10 at 7:05










            • +1 for the awesomeness of using goto AND making the code work without it
              – Akku
              Feb 22 '11 at 13:49


















            • Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
              – Michael Matheus
              Apr 3 '10 at 11:59










            • @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
              – outis
              Apr 3 '10 at 13:14










            • Thanks for checking it out for me.
              – Michael Matheus
              Apr 3 '10 at 14:04










            • Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
              – Michael Matheus
              Apr 4 '10 at 7:05










            • +1 for the awesomeness of using goto AND making the code work without it
              – Akku
              Feb 22 '11 at 13:49
















            Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
            – Michael Matheus
            Apr 3 '10 at 11:59




            Thanks for replying. I think there are two typos in your second snippet. range should be digitRange and the == should be != right? Also, the second snippet finds 2 for the value 12. I'd like to find all positive numbers not regarding their amount of ciphers. Is this also possible with your second snippet or should I go for the regex libraries?
            – Michael Matheus
            Apr 3 '10 at 11:59












            @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
            – outis
            Apr 3 '10 at 13:14




            @Michael: yep. Originally, I had the "string doesn't end with a number" branch first; apparently, I neglected to invert the test. I'll update my answer with a snippet that extracts the entire number for real once I've had some rest.
            – outis
            Apr 3 '10 at 13:14












            Thanks for checking it out for me.
            – Michael Matheus
            Apr 3 '10 at 14:04




            Thanks for checking it out for me.
            – Michael Matheus
            Apr 3 '10 at 14:04












            Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
            – Michael Matheus
            Apr 4 '10 at 7:05




            Thanks a super über giga million times! It contains a typo in substringFromSet:options:range: , range is declared twice there. Removing NSRange from that paragraph did the trick :D
            – Michael Matheus
            Apr 4 '10 at 7:05












            +1 for the awesomeness of using goto AND making the code work without it
            – Akku
            Feb 22 '11 at 13:49




            +1 for the awesomeness of using goto AND making the code work without it
            – Akku
            Feb 22 '11 at 13:49












            up vote
            0
            down vote













            I couldn't get the NSPredicate code above to work correctly, though it looks like it should. Instead I accomplished the same thing with



            if ([string rangeOfString:@"\d+$" options:NSRegularExpressionSearch].location != NSNotFound) {
            // string ends with a number
            }


            Hat-tip to this answer.






            share|improve this answer

























              up vote
              0
              down vote













              I couldn't get the NSPredicate code above to work correctly, though it looks like it should. Instead I accomplished the same thing with



              if ([string rangeOfString:@"\d+$" options:NSRegularExpressionSearch].location != NSNotFound) {
              // string ends with a number
              }


              Hat-tip to this answer.






              share|improve this answer























                up vote
                0
                down vote










                up vote
                0
                down vote









                I couldn't get the NSPredicate code above to work correctly, though it looks like it should. Instead I accomplished the same thing with



                if ([string rangeOfString:@"\d+$" options:NSRegularExpressionSearch].location != NSNotFound) {
                // string ends with a number
                }


                Hat-tip to this answer.






                share|improve this answer












                I couldn't get the NSPredicate code above to work correctly, though it looks like it should. Instead I accomplished the same thing with



                if ([string rangeOfString:@"\d+$" options:NSRegularExpressionSearch].location != NSNotFound) {
                // string ends with a number
                }


                Hat-tip to this answer.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 20 at 1:10









                jab

                3,65822740




                3,65822740






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2570853%2fcheck-if-last-characters-of-an-nsstring-are-numbers%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Wiesbaden

                    Marschland

                    Dieringhausen