Skip to content

Commit 17ef7be

Browse files
committed
Optimize alternation in regular expression. If the validMacros dictionary is the same as last time, don't build the regular expression again.
1 parent e890ca8 commit 17ef7be

File tree

1 file changed

+117
-5
lines changed

1 file changed

+117
-5
lines changed

Core/Source/DTLocalizableStringScanner.m

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,122 @@ @implementation DTLocalizableStringScanner
3030

3131
@synthesize entryFoundCallback=_entryFoundCallback;
3232

33+
34+
- (void) rebuildPattern:(NSMutableString *) pattern withDictionary:(NSDictionary *) node {
35+
NSUInteger count = [node count];
36+
if (count == 0) {
37+
return;
38+
} else if (count == 1) {
39+
for (NSNumber *key in node) {
40+
unichar c = [key unsignedShortValue];
41+
if (c == '|') {
42+
return;
43+
}
44+
45+
CFStringAppendCharacters((__bridge CFMutableStringRef) pattern, &c, 1);
46+
47+
NSDictionary *dict = [node objectForKey:key];
48+
if (dict) {
49+
[self rebuildPattern:pattern withDictionary:dict];
50+
}
51+
}
52+
} else {
53+
BOOL isFirst = [pattern length] == 0;
54+
if (!isFirst) {
55+
[pattern appendString:@"(?:"];
56+
}
57+
58+
BOOL ender = NO;
59+
BOOL firstKey = YES;
60+
61+
NSArray *keys = [[node allKeys] sortedArrayUsingSelector:@selector(compare:)];
62+
for (NSNumber *key in keys) {
63+
unichar c = [key unsignedShortValue];
64+
65+
if (c == '|') {
66+
ender = YES;
67+
} else {
68+
if (!firstKey) {
69+
[pattern appendString:@"|"];
70+
}
71+
firstKey = NO;
72+
73+
CFStringAppendCharacters((__bridge CFMutableStringRef) pattern, &c, 1);
74+
75+
NSDictionary *dict = [node objectForKey:key];
76+
if (dict) {
77+
[self rebuildPattern:pattern withDictionary:dict];
78+
}
79+
}
80+
}
81+
82+
if (!isFirst) {
83+
[pattern appendString:@")"];
84+
if (ender) {
85+
[pattern appendString:@"?"];
86+
}
87+
}
88+
}
89+
}
90+
91+
- (NSString *) optimizedAlternationPatternStringWithValidMacros:(NSDictionary *) validMacros {
92+
NSArray *orderedKeys = [[validMacros allKeys] sortedArrayUsingSelector:@selector(compare:)];
93+
94+
NSMutableDictionary *root = [NSMutableDictionary dictionary];
95+
NSMutableDictionary *node;
96+
97+
for (NSString *key in orderedKeys) {
98+
node = root;
99+
100+
NSUInteger keyLength = [key length];
101+
102+
for (NSUInteger i = 0; i <= keyLength; i++) {
103+
unichar c;
104+
if (i < keyLength) {
105+
c = [key characterAtIndex:i];
106+
} else {
107+
c = '|';
108+
}
109+
110+
// find node for this character
111+
NSMutableDictionary *thisNode = [node objectForKey:[NSNumber numberWithUnsignedShort:c]];
112+
if (!thisNode) {
113+
thisNode = [NSMutableDictionary dictionary];
114+
[node setObject:thisNode forKey:[NSNumber numberWithUnsignedShort:c]];
115+
}
116+
117+
node = thisNode;
118+
}
119+
}
120+
121+
NSMutableString *pattern = [NSMutableString string];
122+
[self rebuildPattern:pattern withDictionary:root];
123+
124+
return pattern;
125+
}
126+
127+
- (NSRegularExpression *) regularExpressionWithValidMacros:(NSDictionary *)validMacros {
128+
@synchronized ([self class]) {
129+
static NSDictionary *lastValidMacrosDictionary = nil;
130+
static NSRegularExpression *lastRegularExpression = nil;
131+
132+
if (lastValidMacrosDictionary == validMacros) {
133+
return lastRegularExpression;
134+
} else {
135+
// build regex to find macro words
136+
NSString *innerPatternPart = [self optimizedAlternationPatternStringWithValidMacros:validMacros];
137+
NSString *pattern = [NSString stringWithFormat:@"\\b(%@)\\b", innerPatternPart];
138+
139+
//NSLog(@"optimized pattern: %@", pattern);
140+
141+
lastValidMacrosDictionary = validMacros;
142+
lastRegularExpression = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
143+
144+
return lastRegularExpression;
145+
}
146+
}
147+
}
148+
33149
- (id)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)encoding validMacros:(NSDictionary *)validMacros
34150
{
35151
self = [super init];
@@ -48,11 +164,7 @@ - (id)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)encoding val
48164
_url = [url copy]; // to have a reference later
49165

50166
_validMacros = validMacros;
51-
52-
// build regex to find macro words
53-
NSString *innerPatternPart = [[validMacros allKeys] componentsJoinedByString:@"|"];
54-
NSString *pattern = [NSString stringWithFormat:@"\\b(%@)\\b", innerPatternPart];
55-
_validMacroRegex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
167+
_validMacroRegex = [self regularExpressionWithValidMacros:validMacros];
56168
}
57169

58170
return self;

0 commit comments

Comments
 (0)