Overview

Classes

  • Horde_Date_Parser
  • Horde_Date_Parser_Handler
  • Horde_Date_Parser_Locale_Base
  • Horde_Date_Parser_Locale_Base_Grabber
  • Horde_Date_Parser_Locale_Base_Ordinal
  • Horde_Date_Parser_Locale_Base_Pointer
  • Horde_Date_Parser_Locale_Base_Repeater
  • Horde_Date_Parser_Locale_Base_Scalar
  • Horde_Date_Parser_Locale_Base_Separator
  • Horde_Date_Parser_Locale_Base_Timezone
  • Horde_Date_Parser_Locale_De
  • Horde_Date_Parser_Locale_De_Grabber
  • Horde_Date_Parser_Locale_De_Ordinal
  • Horde_Date_Parser_Locale_De_Pointer
  • Horde_Date_Parser_Locale_De_Repeater
  • Horde_Date_Parser_Locale_De_Scalar
  • Horde_Date_Parser_Locale_De_Separator
  • Horde_Date_Parser_Locale_De_Timezone
  • Horde_Date_Parser_Locale_Pt
  • Horde_Date_Parser_Locale_Pt_Grabber
  • Horde_Date_Parser_Locale_Pt_Ordinal
  • Horde_Date_Parser_Locale_Pt_Pointer
  • Horde_Date_Parser_Locale_Pt_Repeater
  • Horde_Date_Parser_Locale_Pt_Scalar
  • Horde_Date_Parser_Locale_Pt_Separator
  • Horde_Date_Parser_Locale_Pt_Timezone
  • Horde_Date_Parser_Result
  • Horde_Date_Parser_Token

Exceptions

  • Horde_Date_Parser_Exception
  • Overview
  • Class
  • Tree
  1: <?php 
  2: /**
  3:  */
  4: 
  5: class Horde_Date_Parser_Locale_Pt extends Horde_Date_Parser_Locale_Base
  6: {
  7:     public $definitions = array();
  8:     public $args = array();
  9:     public $now;
 10: 
 11:     public function __construct($args)
 12:     {
 13:         $this->args = $args;
 14:     }
 15: 
 16:     /**
 17:     # Parses a string containing a natural language date or time. If the parser
 18:     # can find a date or time, either a Horde_Date or Horde_Date_Span will be returned
 19:     # (depending on the value of <tt>:return</tt>). If no date or time can be found,
 20:     # +nil+ will be returned.
 21:     #
 22:     # Options are:
 23:     #
 24:     # [<tt>:context</tt>]
 25:     #     <tt>:past</tt> or <tt>:future</tt> (defaults to <tt>:future</tt>)
 26:     #
 27:     #     If your string represents a birthday, you can set <tt>:context</tt> to <tt>:past</tt>
 28:     #     and if an ambiguous string is given, it will assume it is in the
 29:     #     past. Specify <tt>:future</tt> or omit to set a future context.
 30:     #
 31:     # [<tt>:now</tt>]
 32:     #     Time (defaults to time())
 33:     #
 34:     #     By setting <tt>:now</tt> to a Horde_Date, all computations will be based off
 35:     #     of that time instead of time().
 36:     #
 37:     # [<tt>:return</tt>]
 38:     #     'result', 'span', or 'date' (defaults to 'date')
 39:     #
 40:     #     By default, the parser will guess a single point in time for the
 41:     #     given date or time. If you'd rather have the entire time span returned,
 42:     #     set <tt>:return</tt> to 'span' and a Horde_Date_Span will be returned.
 43:     #     If you want the entire result, including tokens (for retrieving the text
 44:     #     that was or was not tagged, for example), set <tt>:return</tt> to 'result'
 45:     #     and you will get a result object.
 46:     #
 47:     # [<tt>:ambiguousTimeRange</tt>]
 48:     #     Integer or <tt>:none</tt> (defaults to <tt>6</tt> (6am-6pm))
 49:     #
 50:     #     If an Integer is given, ambiguous times (like 5:00) will be
 51:     #     assumed to be within the range of that time in the AM to that time
 52:     #     in the PM. For example, if you set it to <tt>7</tt>, then the parser will
 53:     #     look for the time between 7am and 7pm. In the case of 5:00, it would
 54:     #     assume that means 5:00pm. If <tt>:none</tt> is given, no assumption
 55:     #     will be made, and the first matching instance of that time will
 56:     #     be used.
 57:     */
 58:     
 59:     public function parse($text, $specifiedOptions = array())
 60:     {
 61:         // get options and set defaults if necessary
 62:         $defaultOptions = array(
 63:             'context' => 'future',
 64:             'now' => new Horde_Date(time()),
 65:             'return' => 'date',
 66:             'ambiguousTimeRange' => 6,
 67:         );
 68:         $options = array_merge($defaultOptions, $this->args, $specifiedOptions);
 69: 
 70:         // ensure the specified options are valid
 71:         foreach (array_keys($specifiedOptions) as $key) {
 72:             if (!isset($defaultOptions[$key])) {
 73:                 throw new InvalidArgumentException("$key is not a valid option key");
 74:             }
 75:         }
 76: 
 77:         if (!in_array($options['context'], array('past', 'future', 'none'))) {
 78:             throw new InvalidArgumentException("Invalid value " . $options['context'] . " for 'context' specified. Valid values are 'past', 'future', and 'none'");
 79:         }
 80: 
 81:         // store now for later =)
 82:         $this->now = $options['now'];
 83: 
 84: 
 85:         $text = $this->normalize_special_characters($text);
 86: 
 87:         // put the text into a normal format to ease scanning
 88:         $text = $this->preNormalize($text);
 89: 
 90:         // get base tokens for each word
 91:         $tokens = $this->preTokenize($text);
 92: 
 93:         // scan the tokens with each token scanner
 94:         foreach (array('Repeater') as $tokenizer) {
 95:             $tokenizer = $this->componentFactory($tokenizer);
 96:             $tokens = $tokenizer->scan($tokens, $options);
 97:         }
 98: 
 99:         foreach (array('Grabber', 'Pointer', 'Scalar', 'Ordinal', 'Separator', 'Timezone') as $tokenizer) {
100:             $tokenizer = $this->componentFactory($tokenizer);
101:             $tokens = $tokenizer->scan($tokens);
102:         }
103: 
104:         // strip any non-tagged tokens
105:         $taggedTokens = array_values(array_filter($tokens, create_function('$t', 'return $t->tagged();')));
106: 
107:         // Remove tokens we know we don't want - for example, if the first token
108:         // is a separator, drop it.
109:         $taggedTokens = $this->postTokenize($taggedTokens);
110: 
111:         // do the heavy lifting
112:         $span = $this->tokensToSpan($taggedTokens, $options);
113: 
114:         // generate the result and return it, the span, or a guessed time within the span
115:         $result = new Horde_Date_Parser_Result($span, $tokens);
116:         switch ($options['return']) {
117:         case 'result':
118:             return $result;
119:         case 'span':
120:             return $result->span;
121:         case 'date':
122:             return $result->guess();
123:         }
124:     }
125: 
126:     /**
127:     Replaces special characters with non-special equivalents
128:     source: http://pt2.php.net/manual/en/function.chr.php#93291
129:     */
130:     public function normalize_special_characters( $str )
131:     {
132:         # Quotes cleanup
133:         $str = ereg_replace( chr(ord("`")), "'", $str );        # `
134:         $str = ereg_replace( chr(ord("´")), "'", $str );        # ´
135:         $str = ereg_replace( chr(ord("„")), ",", $str );        # „
136:         $str = ereg_replace( chr(ord("`")), "'", $str );        # `
137:         $str = ereg_replace( chr(ord("´")), "'", $str );        # ´
138:         $str = ereg_replace( chr(ord("“")), "\"", $str );       # “
139:         $str = ereg_replace( chr(ord("”")), "\"", $str );       # ”
140:         $str = ereg_replace( chr(ord("´")), "'", $str );        # ´
141: 
142:         $unwanted_array = array('Š'=>'S', 'š'=>'s', 'Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
143:                                 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U',
144:                                 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss', 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c',
145:                                 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o',
146:                                 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y' );
147:         $str = strtr( $str, $unwanted_array );
148: 
149:         # Bullets, dashes, and trademarks
150:         $str = ereg_replace( chr(149), "&#8226;", $str );    # bullet •
151:         $str = ereg_replace( chr(150), "&ndash;", $str );    # en dash
152:         $str = ereg_replace( chr(151), "&mdash;", $str );    # em dash
153:         $str = ereg_replace( chr(153), "&#8482;", $str );    # trademark
154:         $str = ereg_replace( chr(169), "&copy;", $str );     # copyright mark
155:         $str = ereg_replace( chr(174), "&reg;", $str );      # registration mark
156: 
157:         return $str;
158:     }
159: 
160: 
161:     /**
162:     # Clean up the specified input text by stripping unwanted characters,
163:     # converting idioms to their canonical form, converting number words
164:     # to numbers (three => 3), and converting ordinal words to numeric
165:     # ordinals (third => 3rd)
166:     */
167:     public function preNormalize($text)
168:     {
169:         // fix email parser
170:         $text = preg_replace('/\b([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})\b/', '', $text);
171: 
172:         $text = strtolower($text);
173:         $text = $this->numericizeNumbers($text);
174:         // fix url parser
175:         $text = preg_replace('/(?:(?:https?|ftp):\/\/)/', '', $text);
176: 
177:         // composed sentences
178:         $text = preg_replace('/\bsegunda[ \-]feira\b/', 'segunda', $text);
179:         $text = preg_replace('/\bterca[ \-]feira\b/', 'terca', $text);
180:         $text = preg_replace('/\bquarta[ \-]feira\b/', 'quarta', $text);
181:         $text = preg_replace('/\bquinta[ \-]feira\b/', 'quinta', $text);
182:         $text = preg_replace('/\bsexta[ \-]feira\b/', 'sexta', $text);
183: 
184:         $text = preg_replace('/[\'"\.]/', '', $text);
185:         $text = preg_replace('/([\/\-\,\@])/', ' $1 ', $text);
186:         $text = preg_replace('/\bhoje\b/', 'this day', $text);
187:         $text = preg_replace('/\bamanh[aã]\b/', 'next day', $text);
188:         $text = preg_replace('/\bontem\b/', 'last day', $text);
189:         $text = preg_replace('/\bfim de semana\b/', 'fds', $text);
190:         $text = preg_replace('/\bmeio\s+dia\b/', '12:00', $text);
191:         $text = preg_replace('/\bmeia\s+noite\b/', '24:00', $text);
192:         $text = preg_replace('/\b(antes|anterior)\b/', 'past', $text);
193:         $text = preg_replace('/\b(agora|j[aá])\b/', 'this second', $text);
194:         $text = preg_replace('/\b[uú]ltim[oa]\b/', 'last', $text);
195:         $text = preg_replace('/\b(?:de|na|durante\s+a|logo(?:\s[aà]|de))\s+(manh[aã]|madrugada)\b/', 'morning', $text);
196:         $text = preg_replace('/\b(?:de|[àa]|durante\s+a|logo(?:\s[aà]|de))\s+tarde\b/', 'afternoon', $text);
197:         $text = preg_replace('/\b((?:de|[àa]|durante\s+a|logo(?:\s[aà]))\s+noite|(?:ao)\s+anoitecer)\b/', 'this night', $text);
198: 
199:         $text = preg_replace_callback(
200:             '/\b([0-1]?[0-9]|2[0-3])(:|,|.)?([0-5][0-9])?\s?(horas?)\b/',
201:             create_function(
202:                 '$matches',
203:                     '
204:                     $minute = ($matches[3]!="")? str_pad($matches[3], 2 , "0", STR_PAD_LEFT): "00";
205:                     $hour = $matches[1];
206:                     return $hour.":".$minute." oclock";
207:                     '
208:             ),
209:         $text);
210: 
211:         $text = preg_replace('/\b(horas?|h|hrs?)\b/', ' oclock', $text);
212: 
213:         $text = preg_replace('/\b(depois|ap[oó]s)\b/', 'future', $text);
214: 
215:         $text = preg_replace('/\bdia\b/', '', $text);       // broke parser: redundant, ignore and read from number day
216: 
217:         // $text = $this->numericizeNumbers($text);
218: 
219:         return $text;
220:     }
221: 
222:     /**
223:      * Convert ordinal words to numeric ordinals (third => 3rd)
224:      */
225:     public function numericizeOrdinals($text)
226:     {
227:         /*
228:         $text = preg_replace('/^d[eé]cim[oa]\s+primeir[oa]$/', '11º', $text);
229:         $text = preg_replace('/^d[eé]cim[oa]\s+segund[oa]$/', '12º', $text);
230:         $text = preg_replace('/^d[eé]cim[oa]\s+terceir[oa]$/', '13º', $text);
231:         $text = preg_replace('/^d[eé]cim[oa]\s+quart[oa]$/', '14º', $text);
232:         $text = preg_replace('/^d[eé]cim[oa]\s+quint[oa]$/', '15º', $text);
233:         $text = preg_replace('/^d[eé]cim[oa]\s+sext[oa]$/', '16º', $text);
234:         $text = preg_replace('/^d[eé]cim[oa]\s+s[eé]tim[oa]$/', '17º', $text);
235:         $text = preg_replace('/^d[eé]cim[oa]\s+oit[aá]v[oa]$/', '18º', $text);
236:         $text = preg_replace('/^d[eé]cim[oa]\s+^non[oa]$/', '19º', $text);
237:         $text = preg_replace('/^primeir[oa]$/', '1º', $text);
238:         $text = preg_replace('/^segund[oa]$/', '2º', $text);
239:         $text = preg_replace('/^terceir[oa]$/', '3º', $text);
240:         $text = preg_replace('/^quart[oa]$/', '4º', $text);
241:         $text = preg_replace('/^quint[oa]$/', '5º', $text);
242:         $text = preg_replace('/^sext[oa]$/', '6º', $text);
243:         $text = preg_replace('/^s[eé]tim[oa]$/', '7º', $text);
244:         $text = preg_replace('/^oit[aá]v[oa]$/', '8º', $text);
245:         $text = preg_replace('/^non[oa]$/', '9º', $text);
246:         $text = preg_replace('/^d[eé]cim[oa]$/', '10º', $text);
247:         // and so one....
248:         */
249:         return $text;
250:     }
251:     public function initDefinitions()
252:     {
253:         if ($this->definitions) { return; }
254: 
255:         $this->definitions = array(
256:             'time' => array(
257: //                new Horde_Date_Parser_Handler(array(':repeater_time', ':repeater_day_portion?'), null),
258:                 new Horde_Date_Parser_Handler(array(':separator_at?', ':repeater_time', ':repeater_day_portion?'), null),
259:                 new Horde_Date_Parser_Handler(array(':separator_at?', ':time', ':repeater_time'), null),            // ás 10 horas
260: /*
261:                 new Horde_Date_Parser_Handler(array(':repeater_day_portion?', ':repeater_time' ), null),
262:                 new Horde_Date_Parser_Handler(array(':separator_at?', ':repeater_time' ), null),
263:                 new Horde_Date_Parser_Handler(array(':repeater_time', ':separator_at?', ':repeater_day_portion?'), null),
264: */
265:             ),
266: 
267:             'date' => array(
268:                 new Horde_Date_Parser_Handler(array(':repeater_day_name', ':repeater_month_name', ':scalar_day', ':repeater_time', ':timezone', ':scalar_year'), 'handle_rdn_rmn_sd_t_tz_sy'),
269:                 new Horde_Date_Parser_Handler(array(':repeater_month_name', ':scalar_day', ':scalar_year'), 'handle_rmn_sd_sy'),
270:                 new Horde_Date_Parser_Handler(array(':repeater_month_name', ':scalar_day', ':scalar_year', ':separator_at?', 'time?'), 'handle_rmn_sd_sy'),
271:                 new Horde_Date_Parser_Handler(array(':repeater_month_name', ':scalar_day', ':separator_at?', 'time?'), 'handle_rmn_sd'),
272:                 new Horde_Date_Parser_Handler(array(':repeater_month_name', ':ordinal_day', ':separator_at?', 'time?'), 'handle_rmn_od'),
273:                 new Horde_Date_Parser_Handler(array(':repeater_month_name', ':scalar_year'), 'handle_rmn_sy'),
274:                 new Horde_Date_Parser_Handler(array(':scalar_day', ':repeater_month_name', ':scalar_year', ':separator_at?', 'time?'), 'handle_sd_rmn_sy'),
275:                 new Horde_Date_Parser_Handler(array(':scalar_month', ':separator_slash_or_dash', ':scalar_day', ':separator_slash_or_dash', ':scalar_year', ':separator_at?', 'time?'), 'handle_sm_sd_sy'),
276:                 new Horde_Date_Parser_Handler(array(':scalar_day', ':separator_slash_or_dash', ':scalar_month', ':separator_slash_or_dash', ':scalar_year', ':separator_at?', 'time?'), 'handle_sd_sm_sy'),
277:                 new Horde_Date_Parser_Handler(array(':scalar_year', ':separator_slash_or_dash', ':scalar_month', ':separator_slash_or_dash', ':scalar_day', ':separator_at?', 'time?'), 'handle_sy_sm_sd'),
278:                 new Horde_Date_Parser_Handler(array(':scalar_month', ':separator_slash_or_dash', ':scalar_year'), 'handle_sm_sy'),
279:                 new Horde_Date_Parser_Handler(array(':scalar_day', ':separator_at?', ':repeater_month_name', ':separator_at?', ':scalar_year', ':separator_at?', 'time?'), 'handle_sd_rmn_sy'),
280:                 /*
281:                 new Horde_Date_Parser_Handler(array(':scalar_day',  ':separator_at?', ':repeater_month_name', ':separator_at?', 'time?'), 'handle_sd_rmn'),
282:                 new Horde_Date_Parser_Handler(array(':ordinal_day',  ':separator_at?', ':repeater_month_name', ':separator_at?', 'time?'), 'handle_od_rmn'),
283:                 new Horde_Date_Parser_Handler(array(':repeater_day_name',  ':separator_at?', ':time?'), 'handle_rdn'),
284:                 new Horde_Date_Parser_Handler(array(':scalar_day',  ':separator_at?', ':scalar_month', ':separator_at?', ':scalar_year?', 'time?'), 'handle_sd_sm_sy'),
285:                 new Horde_Date_Parser_Handler(array(':scalar_day',  ':separator_at?', ':repeater_month_name', ':separator_at?', ':scalar_year', ':separator_at?', 'time?'), 'handle_sd_rmn_sy'), 
286:                 */
287:                 new Horde_Date_Parser_Handler(array(':scalar_day', ':separator_slash_or_dash', ':scalar_month', ':separator_slash_or_dash', ':scalar_year', ':separator_at?', 'time?'), 'handle_sd_sm_sy'),
288:                 new Horde_Date_Parser_Handler(array(':scalar_year', ':separator_slash_or_dash', ':scalar_month', ':separator_slash_or_dash', ':scalar_day', ':separator_at?', 'time?'), 'handle_sy_sm_sd'),
289:                 new Horde_Date_Parser_Handler(array(':scalar_month', ':separator_slash_or_dash', ':scalar_year'), 'handle_sm_sy'),
290:             ),
291: 
292:             // tonight at 7pm
293:             'anchor' => array(
294:                 new Horde_Date_Parser_Handler(array(':grabber?', ':repeater', ':separator_at?', ':repeater?', ':repeater?'), 'handle_r'),
295:                 new Horde_Date_Parser_Handler(array(':grabber?', ':repeater', ':repeater', ':separator_at?', ':repeater?', ':repeater?'), 'handle_r'),
296:                 new Horde_Date_Parser_Handler(array(':repeater', ':grabber', ':repeater'), 'handle_r_g_r'),
297:             ),
298: 
299:             // 3 weeks from now, in 2 months
300:             'arrow' => array(
301:                 new Horde_Date_Parser_Handler(array(':scalar', ':repeater', ':pointer'), 'handle_s_r_p'),
302:                 new Horde_Date_Parser_Handler(array(':pointer', ':scalar', ':repeater'), 'handle_p_s_r'),
303:                 new Horde_Date_Parser_Handler(array(':scalar', ':repeater', ':pointer', 'anchor'), 'handle_s_r_p_a'),
304:             ),
305: 
306:             // 3rd week in march
307:             'narrow' => array(
308:                 new Horde_Date_Parser_Handler(array(':ordinal', ':repeater', ':separator_in', ':repeater'), 'handle_o_r_s_r'),
309:                 new Horde_Date_Parser_Handler(array(':ordinal', ':repeater', ':grabber', ':repeater'), 'handle_o_r_g_r'),
310:             ),
311:         );
312:     }
313: 
314:     public function handle_rdn($tokens, $options)
315:     {
316:         $day = $tokens[0]->getTag('repeater_day_name');
317: 
318:         try {
319: /*
320:             if ($day == date('j')) {
321:                 $dayStart = new Horde_Date(time());
322:             } else if ($day < date('j')) {
323:                 $month = date('m');
324:                 $year = date('Y');
325:                 $dayStart = new Horde_Date($year, $month, $day);
326:             } else {
327:                 if (date('m') == 12)) {
328:                     $month = 1;
329:                     $year = date('Y')+1;
330:                 } else {
331:                     $month = date('m');
332:                     $year = date('Y');
333:                 }
334:                 $dayStart = new Horde_Date($year, $month, $day);
335:             }
336: */
337:             $dayStart = new Horde_Date(time());
338:             return $this->dayOrTime($dayStart, array($tokens[0]), $options);
339:         } catch (Exception $e) {
340:             return null;
341:         }
342:     }
343: 
344:     // JPC
345:     public function handle_sd_rmn($tokens, $options)
346:     {
347:         return $this->handle_m_d($tokens[1]->getTag('repeater_month_name'), $tokens[0]->getTag('scalar_day'), array_slice($tokens, 2), $options);
348:     }
349: 
350:     public function handle_od_rmn($tokens, $options)
351:     {
352:         return $this->handle_m_d($tokens[1]->getTag('repeater_month_name'), $tokens[0]->getTag('ordinal_day'), array_slice($tokens, 2), $options);
353:     }
354: 
355: 
356: }
357: 
API documentation generated by ApiGen