Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Searching for the words with brackets placed around them in iOS

I am trying to search for all words with brackets around them in a group of text and change it to italic in iOS. I am using this code to search for brackets in the text:

static inline NSRegularExpression * ParenthesisRegularExpression() {
    static NSRegularExpression *_parenthesisRegularExpression = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _parenthesisRegularExpression = [[NSRegularExpression alloc] initWithPattern:@"\\[[^\\(\\)]+\\]" options:NSRegularExpressionCaseInsensitive error:nil];
    });

    return _parenthesisRegularExpression;
}

I am using this to show me the matches:

NSRange matchRange = [result rangeAtIndex:0];
NSString *matchString = [[self.markerPointInfoDictionary objectForKey:@"long_description"] substringWithRange:matchRange];
NSLog(@"%@", matchString);

But it is returning me all the text from the first [ to the last ] in the group of text. There is a lot brackets in between.

I am using this code to change the text to italic:

-(TTTAttributedLabel*)setItalicTextForLabel:(TTTAttributedLabel*)attributedLabel fontSize:(float)Size
{
    [attributedLabel setText:[self.markerPointInfoDictionary objectForKey:@"long_description"] afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString)
     {
         NSRange stringRange = NSMakeRange(0, [mutableAttributedString length]);
         NSRegularExpression *regexp = ParenthesisRegularExpression();
         UIFont *italicSystemFont = [UIFont italicSystemFontOfSize:Size];
         CTFontRef italicFont = CTFontCreateWithName((__bridge CFStringRef)italicSystemFont.fontName, italicSystemFont.pointSize, NULL);
         [regexp enumerateMatchesInString:[mutableAttributedString string] options:0 range:stringRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
             NSRange matchRange = [result rangeAtIndex:0];
             NSString *matchString = [[self.markerPointInfoDictionary objectForKey:@"long_description"] substringWithRange:matchRange];
             NSLog(@"%@", matchString);
             if (italicFont) {
                 [mutableAttributedString removeAttribute:(NSString *)kCTFontAttributeName range:result.range];
                 [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)italicFont range:result.range];
                 CFRelease(italicFont);
                 NSRange range1 = NSMakeRange (result.range.location, 1);
                 NSRange range2 = NSMakeRange (result.range.location + result.range.length -2 , 1);
                 [mutableAttributedString replaceCharactersInRange:range1 withString:@""];
                 [mutableAttributedString replaceCharactersInRange:range2 withString:@""];
             }
         }];
         return mutableAttributedString;
     }];

    return attributedLabel;
}

Btw my Text looks like this:

[hello] welcome [world], my [name] is [lakesh]

The results looks like this:

match string is [hello]
match string is [world]
match string is  is [lak

then crash..

Need some guidance to show me my mistake.

like image 454
lakshmen Avatar asked Feb 17 '23 09:02

lakshmen


1 Answers

I haven't thought about the code you are showing, but your regular expression seems to be too greedy:

@"\\[[^\\(\\)]+\\]"

This matches 1-n characters between brackets "[]". The characters are defined by a character class that says "all characters except paranthesis", i.e. except "()".

In other words, your character class also matches bracket characters. The result is that your expression matches everything in between the first "[" and the last "]".

I suggest you try the following regular expression instead:

@"\\[[^\\[\\]]+\\]"

If you don't have nested brackets, you could even simplify it to this:

@"\\[[^\\]]+\\]"


EDIT

This is a simplified version of your code and the sample input text you provided, but using the regex that I have suggested. In my environment this works perfectly, it prints 4 lines to my debug output window. I don't know what causes your crash, so I suggest you start to simplify your own code step by step until you have found the problem.

NSString* mutableAttributedString = @"[hello] welcome [world], my [name] is [lakesh]";
NSRange stringRange = NSMakeRange(0, [mutableAttributedString length]);
NSRegularExpression* regexp = [[NSRegularExpression alloc] initWithPattern:@"\\[[^\\]]+\\]" options:NSRegularExpressionCaseInsensitive error:nil];
[regexp enumerateMatchesInString:mutableAttributedString
                         options:0
                           range:stringRange
                      usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
 {
   NSRange matchRange = [result rangeAtIndex:0];
   NSString* matchString = [mutableAttributedString substringWithRange:matchRange];
   NSLog(@"%@", matchString);
 }
 ];

The main differences to your code are:

  • I don't work with TTTAttributedLabel
  • I don't use NSMutableAttributedString
  • I don't use self.markerPointInfoDictionary
  • I don't have the if (italicFont) code block

So your problem should be in one of these areas.

like image 59
herzbube Avatar answered May 16 '23 07:05

herzbube