Search a string for a String of a specific format.

Discussion in 'iOS Programming' started by ncaissie, Nov 14, 2013.

  1. ncaissie, Nov 14, 2013
    Last edited by a moderator: Nov 14, 2013

    ncaissie macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #1
    Hi

    I am trying search for specific text from and OCR scan.
    When the text is found it works as planned.
    When the text is not found I get this error.

    Code:
     *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString substringWithRange:]: Range or index out of bounds'
    *** First throw call stack:
    (0x322032a3 0x39f2b97f 0x322031c5 0x32152e69 0x1d1d3 0x1c16f 0x34020ab3 0x340958ef 0x33dcac01 0x3a3424b7 0x3a3471bd 0x321d6f3b 0x32149ebd 0x32149d49 0x35d222eb 0x3405f301 0x19055 0x3a362b20)
    libc++abi.dylib: terminate called throwing an exception


    I know it has something to do with the range but I don't see what it is.

    Code:
    - (void)teststring:(NSString *)OCRText{    
    
        NSError *error = nil;
        NSString *regexString = @"[A-Z]{2}[0-9]{6}[<]";
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionCaseInsensitive error:&error];
        NSString *match = [OCRText substringWithRange:[regex rangeOfFirstMatchInString:OCRText options:NSMatchingCompleted range:NSMakeRange(0, [OCRText  length])]];
        if(match == nil){
            self.Message1.text = @"No passport found";
        }else{
            self.Message1.text = @"Passport ID found" ;
            myDBControler =[databasecontrol alloc];
            if([myDBControler PassportFound:[match substringWithRange:NSMakeRange(0, 8)]]){
                self.Message2.text = @"Passport found in DB";
            }else{
                self.Message2.text = @"Passport not found in DB";
            }
        }
        NSLog(@"Matched string: %@", [match substringWithRange:NSMakeRange(0, 8)]);
    
    }
    Any help would be much appreciated.
     
  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #2
    Turn on exception breakpoints so you can determine which line is causing the issue.

    The problem is that rangeOfFirstString probably returns (NSNotFound, 0), which is an invalid range for a substring, when it returns. You should explicitly check for that before attempting to find a substring with the range.
     
  3. ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #3
    Sorry I forgot to mention that. It breaks on the "NSString *match = [OCRText " line and if I click the play a couple of time it throws the exception.
     
  4. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #4

    This line is the problem:

    Code:
        NSString *match = [OCRText substringWithRange:[regex rangeOfFirstMatchInString:OCRText options:NSMatchingCompleted range:NSMakeRange(0, [OCRText  length])]];
    
    I don't know much about NSRegularExpression objects, but I daresay that if the string is not found, it's going to return an NSRange of {NSNotFound, 0} (The location will be NSNotFound, and the length will be zeros.

    NSNotFound is a synonym for NSIntegerMax. It will not be a legal value as an input for substringWithRange.

    You will need to break that line into multiple steps:

    1. Get a range from your regular expression

    2. Check to see if the location of the resulting range == NSNotFound. If yes, stop since the regular expression was not found.

    3. If and only if you get a valid range from your regular expression, pass, that range to substringWithRange.
     
  5. ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #5
    Thanks for the responses.
    I'm pretty new to objective c.
    I'll try breaking it down.
     
  6. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #6
    Both Duncan and I have already told you exactly which method is causing your problem, why it's causing a problem, and even how to fix it...
     
  7. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #7
    Oops. I missed the fact that you already answered him. Sigh.
     
  8. ncaissie, Nov 14, 2013
    Last edited by a moderator: Nov 14, 2013

    ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #8
    I appreciate the help. But everything I try seems to make Xcode puke.

    Code:
    if([regex rangeOfFirstMatchInString:OCRText options:NSMatchingReportCompletion range:newRange] == NSNotFound){
    
    
    
    NSRange newRange = NSMakeRange(0, [OCRText length]);
     if(newRange == NSNotFound){
    Not sure how else I can break it down.
    Like I said I'm new to C.
    That is why I'm here.


    Code:
    [self ReadByNames:@"P<CANDOE<<JOHN<<<<<<<<<<<<<<<<<<<<<<<<QH496843<OCAN6706158M8312846<<<<<<<<<<<<<<03"];
    
    - (void)ReadByNames:(NSString *)OCRText{
        [OCRText stringByReplacingOccurrencesOfString:@" " withString:@""];
        NSError *error = nil;
        NSString *regexString = @"[<]{1}[A-Z]{1,}[<]{2}[A-Z]{1,}[<]{0}";
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionCaseInsensitive error:&error];
       
        NSRange newRange = NSMakeRange(0, [OCRText length]);
        
        NSString *match = [OCRText substringWithRange:[regex rangeOfFirstMatchInString:OCRText options:NSMatchingReportCompletion range:newRange]];
        
        if(match == NSNotFound){
            match = @"String not found"; 
        }else{
    match = [OCRText substringWithRange:[regex rangeOfFirstMatchInString:OCRText options:NSMatchingReportCompletion range:NSMakeRange(0, [OCRText length])]];  
        }
    }
    
    
     
  9. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #9
  10. ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #10
  11. ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #11
    Fixed :D
    I think.

    Code:
        [OCRText stringByReplacingOccurrencesOfString:@" " withString:@""];
        NSError *error = nil;
        NSString *regexString = @"[<]{1}[A-Z]{1,}[<]{2}[A-Z]{1,}[<]{0}"; 
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionCaseInsensitive error:&error];
        NSRange myRange = NSMakeRange(0,[OCRText length]);
        
        NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:OCRText options:0 range:NSMakeRange(0,[OCRText length])];
        
        NSString *match; 
        
        if (!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0))) {
            match = [OCRText substringWithRange:rangeOfFirstMatch];
            NSLog(@"Matched string: %@", match);
        }else{
            NSLog(@"No passport found");
        }
    Thanks for the pointer! hehe
     
  12. MattInOz, Nov 14, 2013
    Last edited: Nov 14, 2013

    MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #12
    Well seems to read like it's fixed but...

    You have to think about what it's trying to do and it's not that easy.
    Think about the next person to read this and need to understand what it's doing. Bearing in mind that person is likely you in few months after you've forgotten a lot of detail about what you've written.

    There is a way to write your if(test) that reinforces the important things about the test.

    Ask yourself the question. does the answer seem harder than it should?
    if the answer is yes there is probably and easier, cheaper way.
     
  13. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #13


    That code works, but it's needlessly complex and rather hard to read. How about

    Code:
        NSString *match; 
        
        NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString: OCRText 
          options: 0 
          range:   NSMakeRange(0,[OCRText length])];
    
        if (rangeOfFirstMatch.location == NSNotFound) 
        {
            NSLog(@"No passport found");
        }
        else
        {
            match = [OCRText substringWithRange:rangeOfFirstMatch];
            NSLog(@"Matched string: %@", match);
        }
     
  14. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #14
    Or if you know how long a passcode needs to be you could test for the length
    Code:
       ...
    
    
        if (rangeOfFirstMatch.length => kMinPassportLength) 
        {
             match = [OCRText substringWithRange:rangeOfFirstMatch];
            NSLog(@"Matched string: %@", match);  
        }
    
     
  15. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #15
    The bigger issue is we're using Obj-C and not Python, so you're having to essentially check for magic numbers rather than exceptions. I have a tendency to go category crazy when writing Obj-C code just so I can hide a bunch of stupid implementation details that Apple's APIs expose.
     
  16. ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #16
    Thanks

    It's messy and complex because I'm learning as I go.
    I have to find pieces from all over try to understand them and make them work for my situation.

    I appreciate the tips.
     
  17. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #17
    Maybe you should consider stepping away from the real coding for a while and spend some time becoming comfortable with the fundamentals of iOS / Objective-C programming.
     
  18. ncaissie, Nov 15, 2013
    Last edited: Nov 15, 2013

    ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #18
    Thanks but I'm 40 and jumping in is how I learn.
    I comment almost every line I just don't post that.

    At work I'm a Java developer. I took on this side project so I can learn IOS dev. I am an Apple Dev member so I should use it. Also we have 8 iOS devices at home.
    I'm thinking about getting the iPad Air.
     
  19. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #19
    Understood. So, do the suggested approaches to using rangeOfFirstMatchInString: make sense to you?
     
  20. ncaissie thread starter macrumors 6502a

    ncaissie

    Joined:
    Dec 1, 2011
    #20

    Yes I do thanks.

    Learning new computer languages is a passion of mine.
     

Share This Page