Mercurial > projects > ldc
comparison tango/tango/text/locale/Parse.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:5825d48b27d1 | 132:1700239cab2e |
---|---|
1 /******************************************************************************* | |
2 | |
3 copyright: Copyright (c) 2005 John Chapman. All rights reserved | |
4 | |
5 license: BSD style: $(LICENSE) | |
6 | |
7 version: Initial release: 2005 | |
8 | |
9 author: John Chapman | |
10 | |
11 ******************************************************************************/ | |
12 | |
13 module tango.text.locale.Parse; | |
14 | |
15 private import tango.time.WallClock; | |
16 | |
17 private import tango.core.Exception; | |
18 | |
19 private import tango.text.locale.Core; | |
20 | |
21 private import tango.time.chrono.Calendar; | |
22 | |
23 private struct DateTimeParseResult { | |
24 | |
25 int year = -1; | |
26 int month = -1; | |
27 int day = -1; | |
28 int hour; | |
29 int minute; | |
30 int second; | |
31 double fraction; | |
32 int timeMark; | |
33 Calendar calendar; | |
34 TimeSpan timeZoneOffset; | |
35 Time parsedDate; | |
36 | |
37 } | |
38 | |
39 package Time parseTime(char[] s, DateTimeFormat dtf) { | |
40 DateTimeParseResult result; | |
41 if (!tryParseExactMultiple(s, dtf.getAllDateTimePatterns(), dtf, result)) | |
42 throw new IllegalArgumentException("String was not a valid Time."); | |
43 return result.parsedDate; | |
44 } | |
45 | |
46 package Time parseTimeExact(char[] s, char[] format, DateTimeFormat dtf) { | |
47 DateTimeParseResult result; | |
48 if (!tryParseExact(s, format, dtf, result)) | |
49 throw new IllegalArgumentException("String was not a valid Time."); | |
50 return result.parsedDate; | |
51 } | |
52 | |
53 package bool tryParseTime(char[] s, DateTimeFormat dtf, out Time result) { | |
54 result = Time.min; | |
55 DateTimeParseResult resultRecord; | |
56 if (!tryParseExactMultiple(s, dtf.getAllDateTimePatterns(), dtf, resultRecord)) | |
57 return false; | |
58 result = resultRecord.parsedDate; | |
59 return true; | |
60 } | |
61 | |
62 package bool tryParseTimeExact(char[] s, char[] format, DateTimeFormat dtf, out Time result) { | |
63 result = Time.min; | |
64 DateTimeParseResult resultRecord; | |
65 if (!tryParseExact(s, format, dtf, resultRecord)) | |
66 return false; | |
67 result = resultRecord.parsedDate; | |
68 return true; | |
69 } | |
70 | |
71 private bool tryParseExactMultiple(char[] s, char[][] formats, DateTimeFormat dtf, inout DateTimeParseResult result) { | |
72 foreach (char[] format; formats) { | |
73 if (tryParseExact(s, format, dtf, result)) | |
74 return true; | |
75 } | |
76 return false; | |
77 } | |
78 | |
79 private bool tryParseExact(char[] s, char[] pattern, DateTimeFormat dtf, inout DateTimeParseResult result) { | |
80 | |
81 bool doParse() { | |
82 | |
83 int parseDigits(char[] s, inout int pos, int max) { | |
84 int result = s[pos++] - '0'; | |
85 while (max > 1 && pos < s.length && s[pos] >= '0' && s[pos] <= '9') { | |
86 result = result * 10 + s[pos++] - '0'; | |
87 --max; | |
88 } | |
89 return result; | |
90 } | |
91 | |
92 bool parseOne(char[] s, inout int pos, char[] value) { | |
93 if (s[pos .. pos + value.length] != value) | |
94 return false; | |
95 pos += value.length; | |
96 return true; | |
97 } | |
98 | |
99 int parseMultiple(char[] s, inout int pos, char[][] values ...) { | |
100 int result = -1, max; | |
101 foreach (int i, char[] value; values) { | |
102 if (value.length == 0 || s.length - pos < value.length) | |
103 continue; | |
104 | |
105 if (s[pos .. pos + value.length] == value) { | |
106 if (result == 0 || value.length > max) { | |
107 result = i + 1; | |
108 max = value.length; | |
109 } | |
110 } | |
111 } | |
112 pos += max; | |
113 return result; | |
114 } | |
115 | |
116 TimeSpan parseTimeZoneOffset(char[] s, inout int pos) { | |
117 bool sign; | |
118 if (pos < s.length) { | |
119 if (s[pos] == '-') { | |
120 sign = true; | |
121 pos++; | |
122 } | |
123 else if (s[pos] == '+') | |
124 pos++; | |
125 } | |
126 int hour = parseDigits(s, pos, 2); | |
127 int minute; | |
128 if (pos < s.length && s[pos] == ':') { | |
129 pos++; | |
130 minute = parseDigits(s, pos, 2); | |
131 } | |
132 //Due to dmd bug, this doesn't compile | |
133 //TimeSpan result = TimeSpan.hours(hour) + TimeSpan.minutes(minute); | |
134 TimeSpan result = TimeSpan(TimeSpan.TicksPerHour * hour + TimeSpan.TicksPerMinute * minute); | |
135 if (sign) | |
136 result = -result; | |
137 return result; | |
138 } | |
139 | |
140 char[] stringOf(char c, int count = 1) { | |
141 char[] s = new char[count]; | |
142 s[0 .. count] = c; | |
143 return s; | |
144 } | |
145 | |
146 result.calendar = dtf.calendar; | |
147 result.year = result.month = result.day = -1; | |
148 result.hour = result.minute = result.second = 0; | |
149 result.fraction = 0.0; | |
150 | |
151 int pos, i, count; | |
152 char c; | |
153 | |
154 while (pos < pattern.length && i < s.length) { | |
155 c = pattern[pos++]; | |
156 | |
157 if (c == ' ') { | |
158 i++; | |
159 while (i < s.length && s[i] == ' ') | |
160 i++; | |
161 if (i >= s.length) | |
162 break; | |
163 continue; | |
164 } | |
165 | |
166 count = 1; | |
167 | |
168 switch (c) { | |
169 case 'd': case 'm': case 'M': case 'y': | |
170 case 'h': case 'H': case 's': | |
171 case 't': case 'z': | |
172 while (pos < pattern.length && pattern[pos] == c) { | |
173 pos++; | |
174 count++; | |
175 } | |
176 break; | |
177 case ':': | |
178 if (!parseOne(s, i, dtf.timeSeparator)) | |
179 return false; | |
180 continue; | |
181 case '/': | |
182 if (!parseOne(s, i, dtf.dateSeparator)) | |
183 return false; | |
184 continue; | |
185 case '\\': | |
186 if (pos < pattern.length) { | |
187 c = pattern[pos++]; | |
188 if (s[i++] != c) | |
189 return false; | |
190 } | |
191 else | |
192 return false; | |
193 continue; | |
194 case '\'': | |
195 while (pos < pattern.length) { | |
196 c = pattern[pos++]; | |
197 if (c == '\'') | |
198 break; | |
199 if (s[i++] != c) | |
200 return false; | |
201 } | |
202 continue; | |
203 default: | |
204 if (s[i++] != c) | |
205 return false; | |
206 continue; | |
207 } | |
208 | |
209 switch (c) { | |
210 case 'd': // day | |
211 if (count == 1 || count == 2) | |
212 result.day = parseDigits(s, i, 2); | |
213 else if (count == 3) | |
214 result.day = parseMultiple(s, i, dtf.abbreviatedDayNames); | |
215 else | |
216 result.day = parseMultiple(s, i, dtf.dayNames); | |
217 if (result.day == -1) | |
218 return false; | |
219 break; | |
220 case 'M': // month | |
221 if (count == 1 || count == 2) | |
222 result.month = parseDigits(s, i, 2); | |
223 else if (count == 3) | |
224 result.month = parseMultiple(s, i, dtf.abbreviatedMonthNames); | |
225 else | |
226 result.month = parseMultiple(s, i, dtf.monthNames); | |
227 if (result.month == -1) | |
228 return false; | |
229 break; | |
230 case 'y': // year | |
231 if (count == 1 || count == 2) | |
232 result.year = parseDigits(s, i, 2); | |
233 else | |
234 result.year = parseDigits(s, i, 4); | |
235 if (result.year == -1) | |
236 return false; | |
237 break; | |
238 case 'h': // 12-hour clock | |
239 case 'H': // 24-hour clock | |
240 result.hour = parseDigits(s, i, 2); | |
241 break; | |
242 case 'm': // minute | |
243 result.minute = parseDigits(s, i, 2); | |
244 break; | |
245 case 's': // second | |
246 result.second = parseDigits(s, i, 2); | |
247 break; | |
248 case 't': // time mark | |
249 if (count == 1) | |
250 result.timeMark = parseMultiple(s, i, stringOf(dtf.amDesignator[0]), stringOf(dtf.pmDesignator[0])); | |
251 else | |
252 result.timeMark = parseMultiple(s, i, dtf.amDesignator, dtf.pmDesignator); | |
253 break; | |
254 case 'z': | |
255 result.timeZoneOffset = parseTimeZoneOffset(s, i); | |
256 break; | |
257 default: | |
258 break; | |
259 } | |
260 } | |
261 | |
262 if (pos < pattern.length || i < s.length) | |
263 return false; | |
264 | |
265 if (result.timeMark == 1) { // am | |
266 if (result.hour == 12) | |
267 result.hour = 0; | |
268 } | |
269 else if (result.timeMark == 2) { // pm | |
270 if (result.hour < 12) | |
271 result.hour += 12; | |
272 } | |
273 | |
274 // If the input string didn't specify a date part, try to return something meaningful. | |
275 if (result.year == -1 || result.month == -1 || result.day == -1) { | |
276 Time now = WallClock.now; | |
277 if (result.month == -1 && result.day == -1) { | |
278 if (result.year == -1) { | |
279 result.year = result.calendar.getYear(now); | |
280 result.month = result.calendar.getMonth(now); | |
281 result.day = result.calendar.getDayOfMonth(now); | |
282 } | |
283 else | |
284 result.month = result.day = 1; | |
285 } | |
286 else { | |
287 if (result.year == -1) | |
288 result.year = result.calendar.getYear(now); | |
289 if (result.month == -1) | |
290 result.month = 1; | |
291 if (result.day == -1) | |
292 result.day = 1; | |
293 } | |
294 } | |
295 return true; | |
296 } | |
297 | |
298 if (doParse()) { | |
299 result.parsedDate = result.calendar.toTime(result.year, result.month, result.day, result.hour, result.minute, result.second, 0); | |
300 return true; | |
301 } | |
302 return false; | |
303 } |