Skip to content

Commit

Permalink
Added extra matching options
Browse files Browse the repository at this point in the history
Added options to specify extra matching options, that are equivalent of NSRegularExpression's NSMatchingAnchored, NSMatchingWithTransparentBounds, and NSMatchingWithoutAnchoringBounds.
  • Loading branch information
aki-null committed May 22, 2012
1 parent 8a08939 commit e710a6c
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 9 deletions.
23 changes: 18 additions & 5 deletions lib/CocoaRegex.h
Expand Up @@ -4,13 +4,24 @@
#import <Foundation/Foundation.h>

typedef enum {
CocoaRegexCaseInsensitive = 1 << 1,
CocoaRegexAllowCommentsAndWhitespace = 1 << 2,
CocoaRegexAnchorsMatchLines = 1 << 3,
CocoaRegexDotMatchesLineSeparators = 1 << 5,
CocoaRegexUseUnicodeWordBoundaries = 1 << 8,
CocoaRegexCaseInsensitive = 1 << 1,
CocoaRegexAllowCommentsAndWhitespace = 1 << 2,
CocoaRegexAnchorsMatchLines = 1 << 3,
CocoaRegexDotMatchesLineSeparators = 1 << 5,
CocoaRegexUseUnicodeWordBoundaries = 1 << 8,
} CocoaRegexOptions;

typedef enum {
// Specifies that matches are limited to those at the start of the search range.
CocoaRegexMatchingAnchored = 1 << 1,
// Specifies that matching may examine parts of the string beyond the bounds of the search range, for purposes such as word
// boundary detection, lookahead, etc. This constant has no effect if the search range contains the entire string.
CocoaRegexMatchingWithTransparentBounds = 1 << 2,
// Specifies that ^ and $ will not automatically match the beginning and end of the search range, but will still match the
// beginning and end of the entire string. This constant has no effect if the search range contains the entire string.
CocoaRegexMatchingWithoutAnchoringBounds = 1 << 3,
} CocoaRegexMatchingOptions;

@interface CocoaRegex : NSObject <NSCopying>

+ (CocoaRegex*)regexWithPattern:(NSString*)pattern options:(CocoaRegexOptions)options;
Expand All @@ -19,9 +30,11 @@ typedef enum {

- (BOOL)matchesInString:(NSString*)string;
- (BOOL)matchesInString:(NSString*)string range:(NSRange)range;
- (BOOL)matchesInString:(NSString*)string range:(NSRange)range options:(CocoaRegexMatchingOptions)options;

- (NSRange)rangeOfFirstMatchInString:(NSString*)string;
- (NSRange)rangeOfFirstMatchInString:(NSString*)string range:(NSRange)range;
- (NSRange)rangeOfFirstMatchInString:(NSString*)string range:(NSRange)range options:(CocoaRegexMatchingOptions)options;

- (NSUInteger)numberOfMatchingRanges;
- (NSRange)matchingRangeAt:(NSUInteger)index;
Expand Down
39 changes: 35 additions & 4 deletions lib/CocoaRegex.m
Expand Up @@ -34,6 +34,7 @@
} UParseError;

typedef int32_t UErrorCode;
typedef int8_t UBool;

URegularExpression* uregex_open(const UniChar* pattern, int32_t patternLength, uint32_t flags, UParseError* pe, UErrorCode* status);
void uregex_close(URegularExpression* regexp);
Expand All @@ -42,6 +43,7 @@
void uregex_setText(URegularExpression* regexp, const UniChar* text, int32_t textLength, UErrorCode* status);
BOOL uregex_find(URegularExpression* regexp, int32_t startIndex, UErrorCode* status);
BOOL uregex_findNext(URegularExpression* regexp, UErrorCode* status);
UBool uregex_lookingAt(URegularExpression *regexp, int32_t startIndex, UErrorCode *status);
int32_t uregex_replaceAll(URegularExpression* regexp, const UniChar *replacementText, int32_t replacementLength, UniChar * destBuf, int32_t destCapacity, UErrorCode * status);
int32_t uregex_appendReplacement(URegularExpression* regexp, const UniChar* replacementText, int32_t replacementLength, UniChar** destBuf, int32_t* destCapacity, UErrorCode* status);
int32_t uregex_appendTail(URegularExpression* regexp, UniChar** destBuf, int32_t* destCapacity, UErrorCode* status);
Expand All @@ -50,6 +52,8 @@
int32_t uregex_end(URegularExpression* regexp, int32_t groupNum, UErrorCode* status);
const char* u_errorName(UErrorCode status);
void uregex_setRegion(URegularExpression *regexp, int32_t regionStart, int32_t regionLimit, UErrorCode *status);
void uregex_useAnchoringBounds(URegularExpression *regexp, UBool b, UErrorCode *status);
void uregex_useTransparentBounds(URegularExpression *regexp, UBool b, UErrorCode *status);

//
// End of uregex.h.
Expand Down Expand Up @@ -118,20 +122,30 @@ - (void)dealloc

- (BOOL)matchesInString:(NSString *)string
{
return [self matchesInString:string range:NSMakeRange(0, string.length)];
return [self matchesInString:string range:NSMakeRange(0, string.length) options:0];
}

- (BOOL)matchesInString:(NSString*)string range:(NSRange)range
{
return [self rangeOfFirstMatchInString:string range:range].location != NSNotFound;
return [self rangeOfFirstMatchInString:string range:range options:0].location != NSNotFound;
}

- (BOOL)matchesInString:(NSString*)string range:(NSRange)range options:(CocoaRegexMatchingOptions)options
{
return [self rangeOfFirstMatchInString:string range:range options:options].location != NSNotFound;
}

- (NSRange)rangeOfFirstMatchInString:(NSString*)string
{
return [self rangeOfFirstMatchInString:string range:NSMakeRange(0, string.length)];
return [self rangeOfFirstMatchInString:string range:NSMakeRange(0, string.length) options:0];
}

- (NSRange)rangeOfFirstMatchInString:(NSString*)string range:(NSRange)range
{
return [self rangeOfFirstMatchInString:string range:range options:0];
}

- (NSRange)rangeOfFirstMatchInString:(NSString*)string range:(NSRange)range options:(CocoaRegexMatchingOptions)options
{
int len = string.length;
if (!len || !range.length || len <= range.location || len < NSMaxRange(range)) {
Expand All @@ -150,8 +164,25 @@ - (NSRange)rangeOfFirstMatchInString:(NSString*)string range:(NSRange)range
status = 0;
uregex_setRegion(regex, range.location, NSMaxRange(range), &status);

if (options & CocoaRegexMatchingWithoutAnchoringBounds) {
status = 0;
uregex_useAnchoringBounds(regex, FALSE, &status);
}

if (options & CocoaRegexMatchingWithTransparentBounds) {
status = 0;
uregex_useTransparentBounds(regex, TRUE, &status);
}

status = 0;
BOOL res = uregex_find(regex, -1, &status);
BOOL res = NO;

if (options & CocoaRegexMatchingAnchored) {
res = uregex_lookingAt(regex, -1, &status);
} else {
res = uregex_find(regex, -1, &status);
}

if (res) {
return [self matchingRangeAt:0];
}
Expand Down
72 changes: 72 additions & 0 deletions test/CocoaRegexTests.m
Expand Up @@ -70,6 +70,78 @@ - (void)testStartAnchor
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));
}

- (void)testMatchingOptions
{
NSString *pattern = @"^[A-Z0-9]{2}";
CocoaRegex *masterRegex = [[CocoaRegex alloc] initWithPattern:pattern options:0];
#if !__has_feature(objc_arc)
[masterRegex autorelease];
#endif
CocoaRegex *regex;
NSRange r, expected;

// Test various anchoring options
regex = [masterRegex copy];
#if !__has_feature(objc_arc)
[regex autorelease];
#endif
NSString *s = @"A1abZZ BB2ss";
r = [regex rangeOfFirstMatchInString:s range:NSMakeRange(7, s.length - 7) options:CocoaRegexMatchingWithoutAnchoringBounds];
expected = NSMakeRange(NSNotFound, 0);
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));

regex = [masterRegex copy];
#if !__has_feature(objc_arc)
[regex autorelease];
#endif
r = [regex rangeOfFirstMatchInString:s range:NSMakeRange(7, s.length - 7)];
expected = NSMakeRange(7, 2);
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));

regex = [masterRegex copy];
#if !__has_feature(objc_arc)
[regex autorelease];
#endif
s = @"A1abZZ :@#AA";
r = [regex rangeOfFirstMatchInString:s range:NSMakeRange(7, s.length - 7) options:CocoaRegexMatchingAnchored];
expected = NSMakeRange(NSNotFound, 0);
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));

regex = [masterRegex copy];
#if !__has_feature(objc_arc)
[regex autorelease];
#endif
s = @"A1abZZ AA:@#";
r = [regex rangeOfFirstMatchInString:s range:NSMakeRange(7, s.length - 7) options:CocoaRegexMatchingAnchored];
expected = NSMakeRange(7, 2);
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));

// Test CocoaRegexMatchingWithTransparentBounds matching option
pattern = @"test(?!ing)";
masterRegex = [[CocoaRegex alloc] initWithPattern:pattern options:0];
#if !__has_feature(objc_arc)
[masterRegex autorelease];
#endif

regex = [masterRegex copy];
#if !__has_feature(objc_arc)
[regex autorelease];
#endif
s = @"testing";
r = [regex rangeOfFirstMatchInString:s range:NSMakeRange(0, 4)];
expected = NSMakeRange(0, 4);
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));

regex = [masterRegex copy];
#if !__has_feature(objc_arc)
[regex autorelease];
#endif
s = @"testing";
r = [regex rangeOfFirstMatchInString:s range:NSMakeRange(0, 4) options:CocoaRegexMatchingWithTransparentBounds];
expected = NSMakeRange(NSNotFound, 0);
STAssertTrue(NSEqualRanges(expected, r), @"%@ != %@", NSStringFromRange(expected), NSStringFromRange(r));
}

- (void)testStart
{
NSString *pattern = @"[a-z0-9]+";
Expand Down

0 comments on commit e710a6c

Please sign in to comment.