NSRegularExpression replace with lookbehind

Discussion in 'Mac Programming' started by Perkin, Dec 20, 2014.

  1. Perkin macrumors newbie

    Joined:
    Oct 22, 2013
    #1
    I'm using a NSTextview with text in, and stepping through with a regex search highlighting the match result, I then want to replace only some of the results, so I can't do a replace all.

    However in the regex is a lookbehind, so the selection is then not matching again for the replace.

    Any ideas on how to replace just the one match that I want?

    I need to redo the search matching the regex, but with a replace on only the required one.

    the search regex contains:
    Code:
    (?<=([^p]\.) $
    which matches a space before eol char

    The replace is with nothing - so it's removing the space

    Say some sample text (the first three text lines all have a space char at end) is:
    Code:
    p. 
    
    =(small)#. 
    
    p. And Here's an end space. 
    
    that last end space is the only one I want to have replaced.
    The search will only match the 2nd and 3rd text lines.

    The search function is as follows
    Code:
    - (void)searchText:(NSString *)searchString inTextView:(NSTextView *)textView options:(NSRegularExpressionOptions)options
    {
        NSString *allText = textView.string;
    
        NSError *error;
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:searchString options:options error:&error];
    
        NSRange curRange = [[[textView selectedRanges] objectAtIndex:0] rangeValue];
        NSInteger insertion = curRange.location + curRange.length;
        NSRange cursorRange = NSMakeRange(insertion, allText.length - insertion);
        NSRange newSelection = [regex rangeOfFirstMatchInString:allText options:0 range:cursorRange];
    
        if (newSelection.location == NSNotFound) {
            NSLog(@"Not Found!");
            NSBeep();
        } else {
            [textView setSelectedRange:newSelection];
            [textView scrollRangeToVisible:newSelection];
        }
    }
    
    Which is called from
    Code:
    - (IBAction)clickedSearch:(id)sender {
        NSString *searchString = [findSearchField stringValue];
    
        NSInteger searchStringLength = [searchString length];
        if (!searchStringLength > 0) {
            NSBeep();
            return;
        }
        
        [self searchText:searchString inTextView:_textview options:NSRegularExpressionAnchorsMatchLines];
    
    }
    
    and the Replace function is as follows - Which I need to fix - getting more text than just selected
    Code:
    - (IBAction)clickedReplace:(id)sender {
        NSString *searchString = [findSearchField stringValue];
        NSString *replaceString = [findReplaceField stringValue];
        
        NSError *error;
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:searchString options:NSRegularExpressionAnchorsMatchLines error:&error];
        
        NSString *textString = [[_textview string] substringWithRange:[_textview selectedRange]];
        NSString *modifiedString = [regex stringByReplacingMatchesInString:textString options:0 range:NSMakeRange(0, [textString length]) withTemplate:replaceString];
    
        [_textview insertText:modifiedString];
    }
    
     
  2. Perkin thread starter macrumors newbie

    Joined:
    Oct 22, 2013
    #2
    Came up with the following solution

    Code:
    - (IBAction)clickedReplace:(id)sender {
        NSString *searchString = [findSearchField stringValue];
        NSString *replaceString = [findReplaceField stringValue];
        
        NSError *error;
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:searchString options:(NSRegularExpressionAnchorsMatchLines & NSRegularExpressionDotMatchesLineSeparators) error:&error];
        
        NSString *allText = [_textview string];
        NSRange selectedRange = [_textview selectedRange];
        
        NSString *modifiedText = [regex stringByReplacingMatchesInString:allText options:NSMatchingWithTransparentBounds range:selectedRange withTemplate: replaceString];
        
        NSRange alteredRange = NSMakeRange(selectedRange.location, selectedRange.length + (modifiedText.length - allText.length));
        NSString *alteredText = [modifiedText substringWithRange:alteredRange];
        
        [_textview insertText:alteredText];
    }
    
    I also handle the escape chars in the replaceString by using the function I use in this post
     
  3. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #3
    Which match is the one that you want?
     

Share This Page