Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
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.
 
Last edited by a moderator:

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,560
6,059
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.
 

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
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.
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
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.


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.
 

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
Thanks for the responses.
I'm pretty new to objective c.
I'll try breaking it down.
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,560
6,059
Thanks for the responses.
I'm pretty new to objective c.
I'll try breaking it down.

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...
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
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.

Oops. I missed the fact that you already answered him. Sigh.
 

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
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])]];  
    }
}
 
Last edited by a moderator:

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
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
 

MattInOz

macrumors 68030
Jan 19, 2006
2,760
0
Sydney
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.
 
Last edited:

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
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



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);
    }
 

MattInOz

macrumors 68030
Jan 19, 2006
2,760
0
Sydney
That code works, but it's needlessly complex and rather hard to read. How about

...

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);  
    }
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,560
6,059
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.
 

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
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.
 

ncaissie

macrumors 6502a
Original poster
Dec 1, 2011
665
6
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.

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.
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.