Search code examples
objective-ccocoansstringcharacter-replacement

Replace substrings with characters in Cocoa


I'm quite new to Cocoa programming and I'm tiring my best to create a program which will have the user input text into a text field and then press a button. When the button is pressed the text is supposed to replace certain substrings to certain characters. None of the substrings are longer than 2 characters, though some are a single character long. After the replacement has been performed the newly acquired text is to be put into another textfield.

Examples of substring replacements may be that "n" is supposed to be changed to "5", "nj" is supposed to be changed to "g" and "ng" is to be changed to "s". So the text "Inject the syringe now!" would be changed to "Igect the syrise 5ow!"

How can I achieve this in a simple and elegant way? I have tried the following code but it doesn't seem to work.

- (IBAction)convert:(id)sender {
    NSMutableString *x;
    [x setString:[self.input stringValue]];
    NSMutableString *output1;
    [output1 setString:@""];
    NSMutableString *middle;
    middle = [[NSMutableString alloc] init];
    int s;
    unsigned long length = [x length];
    for (s = 0; s < length; s = s + 1) {
        if (s + 2 <= length) {            // if more than or equal to two characters left
            [middle setString:[x substringWithRange:NSMakeRange(s, 2)]];
            if ([middle isEqualToString:@"nj"]) {
                [output1 appendToString:@"g"];
                s = s+1;
            } else if ([middle isEqualToString:@"ng"]) {
                [output1 appendToString:@"s"];
                s = s+1;
            } else {                      // if no two-character sequence matched
                [middle setString:[x substringWithRange:NSMakeRange(s, 1)]];
                if ([middle isEqualToString:@"n"]) {
                    [output1 appendString:@"5"];
                }
            }
        } else {                          // if less than two characters left
            [middle setString:[x substringWithRange:NSMakeRange(s, 1)]];
            if ([middle isEqualToString:@"n"]) {
                [output1 appendString:@"5"];
            }
        }
    }
    [self.output setStringValue:output1];
}

Here, *x is where the text from input goes, *output1 is where the result is stored, *middle consists of the piece of text being tested, and input and output are the NSTextFields.


Solution

  • I guess you could achieve what you want with a quite a few different methods. Here is a simple one:

    1. Define a map for values/replacements
    2. Sort them by length (largest length first)
    3. Match and replace

    Something like this perhaps:

    #import <Foundation/Foundation.h>
    
    NSString * matchAndReplace(NSString *input, NSDictionary *map){
    
        NSMutableString *_input = [input mutableCopy];
    
        // Get all keys sorted by greatest length
        NSArray *keys = [map.allKeys sortedArrayUsingComparator: ^(NSString *key1, NSString *key2) {
            return [@(key2.length) compare:@(key1.length)];
        }];
    
        for (NSString *key in keys) {
            [_input replaceOccurrencesOfString:key
                                    withString:map[key]
                                       options:NSLiteralSearch
                                         range:NSMakeRange(0,_input.length)];
        }
        return [_input copy];
    
    };
    
    int main(int argc, char *argv[]) {
        @autoreleasepool {
            NSDictionary *mapping = @{
                @"n": @"5",
                @"nj": @"g",
                @"ng": @"s"
            };
    
            NSString *input = @"Inject the syringe now!";
    
            NSLog(@"Output: %@", matchAndReplace(input, mapping));
        }
    }
    

    Which will produce:

    Output: Igect the syrise 5ow!

    Note: This is an over-simplified way to achieve what you want (obviously) and maybe requires a few adjustments to cover every edge case, but it's simpler than your version and I hope that will be helpful to you.