Replacing a substring in an NSString

Discussion in 'Mac Programming' started by Starfox, Dec 9, 2012.

  1. Starfox macrumors 6502


    Apr 7, 2011
    I've been trying to replace a substring of an NSString and it has been driving me crazy - the problem is the edge case where characters in the string take more than one UTF-16 codepoints, like Emoji. characterAtIndex: is kind of useless in this case and my best solution was going character by character getting the ranges for UTF-chars but my code seems to crash with out-of-range exceptions. Could anyone lend me a second pair of eyes? Code is at
  2. chown33 macrumors 604

    Aug 9, 2009
    Sailing beyond the sunset
    Post the stack-trace of the crash.

    Have you tried using the debugger? Set a breakpoint at the start of the function/method, then step through the code one line at a time.
  3. gnasher729 macrumors P6


    Nov 25, 2005
    First, you can't modify an NSString. You can only modify an NSMutableString.
    Second, methods like "replaceOccurencesOfString" should help you. With Unicode, the higher level functions you use, the better.
  4. ytk macrumors regular

    Jul 8, 2010
    You're totally reinventing the wheel here.

    Just convert the string into an NSMutableString via [NSMutableString stringWithString:], then use NSMutableString's replaceCharactersInRange:withString: method.
  5. Starfox thread starter macrumors 6502


    Apr 7, 2011
    You barely read anything I typed, didn't you now?..
  6. jamawa macrumors newbie

    Jul 7, 2009
    Looking at the code and given the out-of-range errors; you might want to have a look at the value of EndIndex. Unless it is meant to indicate the character after the last character of 'range' instead of the last character itself.

    As Chown33 suggested: walk through the code with the debugger and verify the values of the variables with what you expect them to be.
    NextIndex is one to watch as it is used to get a character from an index without verifying whether NextIndex is indeed a valid index. The values of all variables called range is another.
    It seems likely that one of those is the cause of the error.
  7. ytk macrumors regular

    Jul 8, 2010
    No need to be rude.

    I read exactly what you typed. You're fundamentally just trying to replace part of an NSString with another string. Regardless of what issue you're trying to work around, why are you reimplementing replaceCharactersInRange:withString: when that method already exists? Try writing a function (or subclass NSMutableString and write a method) to correctly determine the part of the string that needs to be replaced, then use the built-in method to do the actual replacement.

    If you do it that way, and the built-in method still doesn't work the way you need it to, then you can reimplement it as a separate function instead of chopping it up and blending it into one big function the way you have it now. You'll find doing so makes bugs much easier to track down.
  8. gnasher729 macrumors P6


    Nov 25, 2005
    Please don't subclass NSString or NSMutableString. Just don't.
  9. ytk macrumors regular

    Jul 8, 2010
    Okay, so use a category to add a method to NSString. Or write a function I guess, but functions are so déclassé. Either way, what you don't want to do is roll the functionality to determine the replacement subset along with the kludgey reimplementation of an existing method to build a new string into a single function.
  10. Senor Cuete, Dec 13, 2012
    Last edited: Dec 13, 2012

    Senor Cuete macrumors 6502

    Nov 9, 2011

    Looking at the index of my Objective-C Pocket Reference I can't find any listing for the keyword "auto".

    Since this builds I assume that the auto declaration is legitimate. What does auto mean? Did this appear in Objective-C 2 or otherwise become part of Objective-C after my book was printed?

    Woops, I see that this is written in C++. And yes you shouldn't subclass NSString and you can't edit an NSString. If you are learning to program OS X or iOS why not use Objective-C?
  11. gnasher729 macrumors P6


    Nov 25, 2005
    Before C++11, "auto" is a storage class like "extern", "static" and "register". It is the storage class for local variables in a function. So instead of having a variable "int x;" in a function you could write "auto int x;" and it means exactly the same thing.

    In C++11, they introduced a new meaning: If you have a declaration with an initializer, you don't have to write the type if you use auto. For example, "auto x = 3.0;" means that x is double, because 3.0 is double. Or "auto x = @"Hello"; " means x is an NSString* because @"Hello" is an NSString*.
  12. Sydde macrumors 68020


    Aug 17, 2009
    As ytk said, it is hard to understand why Starfox is going to so much trouble to replicate a built-in function (NSString method). The method that creates a new string by replacing a substring is only available since 10.5, so I could possibly see the extreme need to insure compatibility with a six-year-old version of OS X, but even then, there are very simple ways to dice up and reassemble a string that do not involve stepping through a loop (at most, 5 or 6 lines of code, given range checking). NSString handles code points of various encodings quite well of its own accord, there is no practical need to muck around inside strings, just let the object do what it is good at.
  13. hchung macrumors 6502a

    Oct 2, 2008
    Do you have an example where replaceOccurencesOfString:withString: does not work with a double-byte characters?

    Can you give an example input to your posted code that fails?
  14. Starfox thread starter macrumors 6502


    Apr 7, 2011
    I managed to solve the issue by adding special code to cater for Emoji. The problem was that I'm trying to replace a range (not an occurence) and the way ranges were reported (from Twitter's API, if that matters) never properly accounted for Emoji. You can see the bug yourself if you use Twitter for Mac and post a tweet with Emoji (especially problematic: emoji flags, since they take four 16-bit "characters" to store in an NSString). Thanks for the help everyone.

Share This Page