-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathUtils.m
219 lines (180 loc) · 11.4 KB
/
Utils.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#import "Utils.h"
NSInteger indexOf(NSString *string, NSString *substring) {
NSRange range = [string rangeOfString:substring];
if (range.location > 0) return range.location;
return NSNotFound;
}
NSRange rangeOfNthOccurrence(NSString *string, NSString *substring, NSInteger occurrence) {
if (occurrence <= 0 || string.length == 0 || substring.length == 0) {
return NSMakeRange(NSNotFound, 0);
}
NSRange searchRange = NSMakeRange(0, string.length);
NSRange foundRange = NSMakeRange(NSNotFound, 0);
for (NSInteger i = 0; i < occurrence; i++) {
NSRange range = [string rangeOfString:substring options:0 range:searchRange];
if (range.location == NSNotFound) {
return NSMakeRange(NSNotFound, 0);
}
foundRange = range;
searchRange = NSMakeRange(NSMaxRange(range), string.length - NSMaxRange(range));
}
return foundRange;
}
NSString *superscript(NSString *string) {
return [NSString stringWithFormat:@">>%@>>", string];
}
NSString *subscript(NSString *string) {
return [NSString stringWithFormat:@"<<%@<<", string];
}
NSString *relativeDateFormat(NSDate *date) {
NSString *day;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
if ([[NSCalendar currentCalendar] isDateInToday:date]) {
day = @"Today";
} else if ([[NSCalendar currentCalendar] isDateInYesterday:date]) {
day = @"Yesterday";
} else {
[dateFormatter setDateFormat:@"MMM d, yyyy"];
day = [dateFormatter stringFromDate:date];
}
[dateFormatter setDateFormat:@"h:mm a"];
NSString *time = [dateFormatter stringFromDate:date];
return [NSString stringWithFormat:@"%@||%@", day, time];
}
bool isLabelTruncated(UILabel *label) {
CGSize size = [label.text sizeWithAttributes:@{NSFontAttributeName: label.font}];
return size.width > label.frame.size.width;
}
NSAttributedString *formatExpression(NSString *equation) {
NSString *regexPattern = @"E\\d+";
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:regexPattern options:0 error:nil];
NSArray *matches = [regex matchesInString:equation options:0 range:NSMakeRange(0, equation.length)];
for (NSInteger i = matches.count - 1; i >= 0; i--) {
NSTextCheckingResult *match = matches[i];
NSRange matchRange = [match range];
NSString *matchString = [equation substringWithRange:matchRange];
equation = [equation stringByReplacingCharactersInRange:matchRange withString:[NSString stringWithFormat:@"×10>>%@>>", [matchString substringFromIndex:1]]];
}
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:equation attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:20]}];
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor systemOrangeColor] range:NSMakeRange(0, indexOf(equation, @"=") + 1)];
NSRegularExpression *superScriptRegex = [NSRegularExpression regularExpressionWithPattern:@">>(.*?)>>" options:NSRegularExpressionCaseInsensitive error:nil];
NSArray<NSTextCheckingResult *> *superScriptMatches = [superScriptRegex matchesInString:[attributedString string] options:0 range:NSMakeRange(0, [[attributedString string] length])];
for (NSTextCheckingResult *match in superScriptMatches) {
NSRange matchRange = [match rangeAtIndex:1];
[attributedString addAttributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:12], NSBaselineOffsetAttributeName: @10} range:matchRange];
}
NSRegularExpression *subScriptRegex = [NSRegularExpression regularExpressionWithPattern:@"<<(.*?)<<" options:NSRegularExpressionCaseInsensitive error:nil];
NSArray<NSTextCheckingResult *> *subScriptMatches = [subScriptRegex matchesInString:[attributedString string] options:0 range:NSMakeRange(0, [[attributedString string] length])];
for (NSTextCheckingResult *match in subScriptMatches) {
NSRange matchRange = [match rangeAtIndex:1];
[attributedString addAttributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:12], NSBaselineOffsetAttributeName: @(-10)} range:matchRange];
}
[attributedString.mutableString replaceOccurrencesOfString:@"<<" withString:@"" options:0 range:NSMakeRange(0, [attributedString.mutableString length])];
[attributedString.mutableString replaceOccurrencesOfString:@">>" withString:@"" options:0 range:NSMakeRange(0, [attributedString.mutableString length])];
return attributedString;
}
NSString *parseExpression(NSString *expression) {
NSLog(@"[calc] parsing expression: %@", expression);
if ([expression isEqualToString:@"pi"] || [expression isEqualToString:@"exp(1)"]) return @"";
expression = [expression stringByReplacingOccurrencesOfString:@"3.141592653589793238462643383279503" withString:@"π"];
expression = [expression stringByReplacingOccurrencesOfString:@"2.718281828459045235360287471352662" withString:@"e"];
if (specialBehavior == kRadical && (![expression containsString:@"pow"] || ![expression containsString:@"/"])) {
NSLog(@"[calc] invalidating specialB");
specialBehavior = kInvalid;
}
if ([expression containsString:@"pow("] && [expression containsString:@")*("]) specialBehavior = kScientificNotation;
if (specialBehavior == kLogarithm && ![expression containsString:@"log("]) specialBehavior = kInvalid;
if ([expression containsString:@"log("]) specialBehavior = kLogarithm;
if ([expression containsString:@"pow("] && [expression containsString:@"1.0/"]) {
NSLog(@"[calc] power with inverse");
NSArray *components = [expression componentsSeparatedByString:@",(1.0/"];
NSString *radicand = [components.firstObject componentsSeparatedByString:@"pow("].lastObject;
NSString *index = [components.lastObject stringByReplacingOccurrencesOfString:@"))" withString:@""];
NSLog(@"[calc] components: %@", components);
NSLog(@"[calc] radicand: %@", radicand);
NSLog(@"[calc] index: %@", index);
NSString *fom = [NSString stringWithFormat:@"%@√(%@)", superscript(index), radicand];
NSLog(@"[calc] formatted: %@", fom);
return fom;
}
switch (specialBehavior) {
case kPercent:
specialBehavior = kInvalid;
expression = [expression componentsSeparatedByString:@"/"].firstObject;
expression = [expression stringByReplacingOccurrencesOfString:@"(" withString:@""];
expression = [expression stringByReplacingOccurrencesOfString:@")" withString:@""];
expression = [NSString stringWithFormat:@"%@\uFF05", expression];
if ([expression isEqualToString:@"0\uFF05"]) return @"";
return expression;
case kRadical: {
NSLog(@"[calc] using radical");
specialBehavior = kInvalid;
NSArray *components = [expression componentsSeparatedByString:@","];
NSString *radicand = [components.firstObject componentsSeparatedByString:@"("].lastObject;
if ([radicand isEqualToString:@"0"]) return @"";
NSString *index = [components.lastObject componentsSeparatedByString:@"/"].lastObject;
index = [index stringByReplacingOccurrencesOfString:@")" withString:@""];
if ([index isEqualToString:@"2"]) return [NSString stringWithFormat:@"√(%@)", radicand];
if ([index isEqualToString:@"3"]) return [NSString stringWithFormat:@"∛(%@)", radicand];
NSLog(@"[calc] %@ sqrt(%@)", index, radicand);
return [NSString stringWithFormat:@"%@√(%@)", superscript(index), radicand];
}
case kInverse:
expression = [[expression componentsSeparatedByString:@"("].lastObject stringByReplacingOccurrencesOfString:@")" withString:@""];
return [NSString stringWithFormat:@"%@>>-1>>", expression];
case kScientificNotation: {
specialBehavior = kInvalid;
NSArray *components = [expression componentsSeparatedByString:@")*("];
NSString *coefficient = [components.lastObject stringByReplacingOccurrencesOfString:@")" withString:@""];
NSString *exponent = [components.firstObject componentsSeparatedByString:@","].lastObject;
return [NSString stringWithFormat:@"%@×10%@", coefficient, superscript(exponent)];
}
case kLogarithm: {
specialBehavior = kInvalid;
NSArray *components = [expression componentsSeparatedByString:@"log("];
NSString *base = [components.lastObject stringByReplacingOccurrencesOfString:@")" withString:@""];
NSString *argument = [[components[1] componentsSeparatedByString:@"("].lastObject stringByReplacingOccurrencesOfString:@")/" withString:@""];
return [NSString stringWithFormat:@"log%@(%@)", subscript(base), argument];
}
}
NSCharacterSet *validChars = [NSCharacterSet characterSetWithCharactersInString:@"abcdfghijklmnopqrstuvwxyz"];
bool basicExpression = ([expression.lowercaseString rangeOfCharacterFromSet:validChars].location == NSNotFound);
if (basicExpression) {
expression = [expression stringByReplacingOccurrencesOfString:@"(" withString:@" "];
expression = [expression stringByReplacingOccurrencesOfString:@")" withString:@" "];
expression = [expression stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
expression = [expression stringByReplacingOccurrencesOfString:@"*" withString:@"×"];
expression = [expression stringByReplacingOccurrencesOfString:@"/" withString:@"÷"];
} else {
NSArray *components = [expression componentsSeparatedByString:@"("];
if ([components.firstObject isEqualToString:@"exp"]) {
expression = [NSString stringWithFormat:@"e%@", superscript([components.lastObject componentsSeparatedByString:@")"].firstObject)];
} else if ([components.firstObject isEqualToString:@"pow"]) {
NSString *base = [components.lastObject componentsSeparatedByString:@","].firstObject;
NSString *exponent = [[[components.lastObject componentsSeparatedByString:@","].lastObject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]stringByReplacingOccurrencesOfString:@")" withString:@""];
expression = [NSString stringWithFormat:@"%@%@", base, superscript(exponent)];
}
for (NSString *trigFunction in @[@"sin", @"cos", @"tan"]) {
if ([components.firstObject containsString:trigFunction]) {
NSString *function = [components.firstObject stringByReplacingOccurrencesOfString:@"d" withString:@""];
if ([components.firstObject hasPrefix:@"a"]) {
function = [function substringFromIndex:[@"a" length]];
function = [NSString stringWithFormat:@"%@⁻¹", function];
}
expression = [NSString stringWithFormat:@"%@(%@", function, components.lastObject];
}
}
}
NSLog(@"[calc] final expression: %@", expression);
return expression;
}
@implementation UIFont (Rounded)
+ (UIFont *)roundedFontOfSize:(CGFloat)size weight:(UIFontWeight)weight {
UIFont *systemFont = [UIFont systemFontOfSize:size weight:weight];
UIFontDescriptor *descriptor = [systemFont.fontDescriptor fontDescriptorWithDesign:UIFontDescriptorSystemDesignRounded];
if (descriptor) {
return [UIFont fontWithDescriptor:descriptor size:size];
}
return systemFont;
}
@end