-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathSuggestion.m
192 lines (166 loc) · 7.24 KB
/
Suggestion.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//
// AvroKeyboard
//
// Created by Rifat Nabi on 6/28/12.
// Copyright (c) 2012 OmicronLab. All rights reserved.
//
#import "Suggestion.h"
#import "AvroParser.h"
#import "AutoCorrect.h"
#import "RegexParser.h"
#import "Database.h"
#import "NSString+Levenshtein.h"
#import "CacheManager.h"
#import "RegexKitLite.h"
static Suggestion* sharedInstance = nil;
@implementation Suggestion
+ (Suggestion *)sharedInstance {
if (sharedInstance == nil) {
[[self alloc] init]; // assignment not done here, see allocWithZone
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
return sharedInstance; // assignment and return on first allocation
}
return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (oneway void)release {
//do nothing
}
- (id)autorelease {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax; // This is sooo not zero
}
- (id)init {
self = [super init];
if (self) {
_suggestions = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
}
- (void)dealloc {
[_suggestions release];
[super dealloc];
}
- (NSMutableArray*)getList:(NSString*)term {
if (term && [term length] == 0) {
return _suggestions;
}
// Suggestions from Default Parser
NSString* paresedString = [[AvroParser sharedInstance] parse:term];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"IncludeDictionary"]) {
// Saving humanity by reducing a few CPU cycles
[_suggestions addObjectsFromArray:[[CacheManager sharedInstance] arrayForKey:term]];
if (_suggestions && [_suggestions count] == 0) {
// Suggestions form AutoCorrect
NSString* autoCorrect = [[AutoCorrect sharedInstance] find:term];
if (autoCorrect) {
[_suggestions addObject:autoCorrect];
}
// Suggestions from Dictionary
NSArray* dicList = [[Database sharedInstance] find:term];
if (dicList) {
// Remove autoCorrect if it is already in the dictionary
// PROPOSAL: don't add the autoCorrect, which matches with the dictionary entry
if (autoCorrect && [dicList containsObject:autoCorrect]) {
[_suggestions removeObjectIdenticalTo:autoCorrect];
}
// Sort dicList based on edit distance
NSArray* sortedDicList = [dicList sortedArrayUsingComparator:^NSComparisonResult(id left, id right) {
int dist1 = [paresedString computeLevenshteinDistanceWithString:(NSString*)left];
int dist2 = [paresedString computeLevenshteinDistanceWithString:(NSString*)right];
if (dist1 < dist2) {
return NSOrderedAscending;
}
else if (dist1 > dist2) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
[_suggestions addObjectsFromArray:sortedDicList];
}
[[CacheManager sharedInstance] setArray:[[_suggestions copy] autorelease] forKey:term];
}
// Suggestions with Suffix
NSInteger i;
BOOL alreadySelected = FALSE;
[[CacheManager sharedInstance] removeAllBase];
for (i = [term length]-1; i > 0; --i) {
NSString* suffix = [[Database sharedInstance] banglaForSuffix:[[term substringFromIndex:i] lowercaseString]];
if (suffix) {
NSString* base = [term substringToIndex:i];
NSArray* cached = [[CacheManager sharedInstance] arrayForKey:base];
NSString* selected;
if (!alreadySelected) {
// Base user selection
selected = [[CacheManager sharedInstance] stringForKey:base];
}
// This should always exist, so it's just a safety check
if (cached) {
for (NSString *item in cached) {
// Skip AutoCorrect English Entry
if ([base isEqualToString:item]) {
continue;
}
NSString* word;
// Again saving humanity cause I'm Superman, no I'm not drunk or on weed :D
NSInteger cutPos = [item length] - 1;
NSString* itemRMC = [item substringFromIndex:cutPos]; // RMC is Right Most Character
NSString* suffixLMC = [suffix substringToIndex:1]; // LMC is Left Most Character
// BEGIN :: This part was taken from http://d.pr/zTmF
if ([self isVowel:itemRMC] && [self isKar:suffixLMC]) {
word = [NSString stringWithFormat:@"%@\u09df%@", item ,suffix];
}
else {
if ([itemRMC isEqualToString:@"\u09ce"]) {
word = [NSString stringWithFormat:@"%@\u09a4%@", [item substringToIndex:cutPos], suffix];
}
else if ([itemRMC isEqualToString:@"\u0982"]) {
word = [NSString stringWithFormat:@"%@\u0999%@", [item substringToIndex:cutPos], suffix];
} else {
word = [NSString stringWithFormat:@"%@%@", item, suffix];
}
}
// END
// Reverse Suffix Caching
[[CacheManager sharedInstance] setBase:[NSArray arrayWithObjects:base, item, nil] forKey:word];
// Check that the WORD is not already in the list
if (![_suggestions containsObject:word]) {
// Intelligent Selection
if (!alreadySelected && selected && [item isEqualToString:selected]) {
if (![[CacheManager sharedInstance] stringForKey:term]) {
[[CacheManager sharedInstance] setString:word forKey:term];
}
alreadySelected = TRUE;
}
[_suggestions addObject:word];
}
}
}
}
}
}
if ([_suggestions containsObject:paresedString] == NO) {
[_suggestions addObject:paresedString];
}
return _suggestions;
}
- (BOOL)isKar:(NSString*)letter {
return [letter isMatchedByRegex:@"^[\u09be\u09bf\u09c0\u09c1\u09c2\u09c3\u09c7\u09c8\u09cb\u09cc\u09c4]$"];
}
- (BOOL)isVowel:(NSString*)letter {
return [letter isMatchedByRegex:@"^[\u0985\u0986\u0987\u0988\u0989\u098a\u098b\u098f\u0990\u0993\u0994\u098c\u09e1\u09be\u09bf\u09c0\u09c1\u09c2\u09c3\u09c7\u09c8\u09cb\u09cc]$"];
}
@end