Packages

  • Nette
    • Application
      • Application\Diagnostics
      • Application\Responses
      • Application\Routers
      • Application\UI
    • Caching
      • Caching\Storages
    • ComponentModel
    • Config
    • Database
      • Database\Diagnostics
      • Database\Drivers
      • Database\Reflection
      • Database\Table
    • DI
    • Diagnostics
    • Forms
      • Forms\Controls
      • Forms\Rendering
    • Http
    • Iterators
    • Latte
      • Latte\Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • None
  • PHP

Classes

  • NArrays
  • NCriticalSection
  • NFinder
  • NHtml
  • NJson
  • NLimitedScope
  • NMimeTypeDetector
  • NNeon
  • NPaginator
  • NStrings

Exceptions

  • NJsonException
  • NNeonException
  • NRegexpException
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004, 2011 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Utils
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * String tools library.
 17:  *
 18:  * @author     David Grudl
 19:  * @package Nette\Utils
 20:  */
 21: class NStrings
 22: {
 23: 
 24:     /**
 25:      * Static class - cannot be instantiated.
 26:      */
 27:     final public function __construct()
 28:     {
 29:         throw new NStaticClassException;
 30:     }
 31: 
 32: 
 33: 
 34:     /**
 35:      * Checks if the string is valid for the specified encoding.
 36:      * @param  string  byte stream to check
 37:      * @param  string  expected encoding
 38:      * @return bool
 39:      */
 40:     public static function checkEncoding($s, $encoding = 'UTF-8')
 41:     {
 42:         return $s === self::fixEncoding($s, $encoding);
 43:     }
 44: 
 45: 
 46: 
 47:     /**
 48:      * Returns correctly encoded string.
 49:      * @param  string  byte stream to fix
 50:      * @param  string  encoding
 51:      * @return string
 52:      */
 53:     public static function fixEncoding($s, $encoding = 'UTF-8')
 54:     {
 55:         // removes xD800-xDFFF, xFEFF, xFFFF, x110000 and higher
 56:         $s = @iconv('UTF-16', $encoding . '//IGNORE', iconv($encoding, 'UTF-16//IGNORE', $s)); // intentionally @
 57:         return str_replace("\xEF\xBB\xBF", '', $s); // remove UTF-8 BOM
 58:     }
 59: 
 60: 
 61: 
 62:     /**
 63:      * Returns a specific character.
 64:      * @param  int     codepoint
 65:      * @param  string  encoding
 66:      * @return string
 67:      */
 68:     public static function chr($code, $encoding = 'UTF-8')
 69:     {
 70:         return iconv('UTF-32BE', $encoding . '//IGNORE', pack('N', $code));
 71:     }
 72: 
 73: 
 74: 
 75:     /**
 76:      * Starts the $haystack string with the prefix $needle?
 77:      * @param  string
 78:      * @param  string
 79:      * @return bool
 80:      */
 81:     public static function startsWith($haystack, $needle)
 82:     {
 83:         return strncmp($haystack, $needle, strlen($needle)) === 0;
 84:     }
 85: 
 86: 
 87: 
 88:     /**
 89:      * Ends the $haystack string with the suffix $needle?
 90:      * @param  string
 91:      * @param  string
 92:      * @return bool
 93:      */
 94:     public static function endsWith($haystack, $needle)
 95:     {
 96:         return strlen($needle) === 0 || substr($haystack, -strlen($needle)) === $needle;
 97:     }
 98: 
 99: 
100: 
101:     /**
102:      * Removes special controls characters and normalizes line endings and spaces.
103:      * @param  string  UTF-8 encoding or 8-bit
104:      * @return string
105:      */
106:     public static function normalize($s)
107:     {
108:         // standardize line endings to unix-like
109:         $s = str_replace("\r\n", "\n", $s); // DOS
110:         $s = strtr($s, "\r", "\n"); // Mac
111: 
112:         // remove control characters; leave \t + \n
113:         $s = preg_replace('#[\x00-\x08\x0B-\x1F\x7F]+#', '', $s);
114: 
115:         // right trim
116:         $s = preg_replace("#[\t ]+$#m", '', $s);
117: 
118:         // trailing spaces
119:         $s = trim($s, "\n");
120: 
121:         return $s;
122:     }
123: 
124: 
125: 
126:     /**
127:      * Converts to ASCII.
128:      * @param  string  UTF-8 encoding
129:      * @return string  ASCII
130:      */
131:     public static function toAscii($s)
132:     {
133:         $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', '', $s);
134:         $s = strtr($s, '`\'"^~', "\x01\x02\x03\x04\x05");
135:         if (ICONV_IMPL === 'glibc') {
136:             $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT', $s); // intentionally @
137:             $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e"
138:                 . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
139:                 . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
140:                 . "\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe",
141:                 "ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt");
142:         } else {
143:             $s = @iconv('UTF-8', 'ASCII//TRANSLIT', $s); // intentionally @
144:         }
145:         $s = str_replace(array('`', "'", '"', '^', '~'), '', $s);
146:         return strtr($s, "\x01\x02\x03\x04\x05", '`\'"^~');
147:     }
148: 
149: 
150: 
151:     /**
152:      * Converts to web safe characters [a-z0-9-] text.
153:      * @param  string  UTF-8 encoding
154:      * @param  string  allowed characters
155:      * @param  bool
156:      * @return string
157:      */
158:     public static function webalize($s, $charlist = NULL, $lower = TRUE)
159:     {
160:         $s = self::toAscii($s);
161:         if ($lower) {
162:             $s = strtolower($s);
163:         }
164:         $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s);
165:         $s = trim($s, '-');
166:         return $s;
167:     }
168: 
169: 
170: 
171:     /**
172:      * Truncates string to maximal length.
173:      * @param  string  UTF-8 encoding
174:      * @param  int
175:      * @param  string  UTF-8 encoding
176:      * @return string
177:      */
178:     public static function truncate($s, $maxLen, $append = "\xE2\x80\xA6")
179:     {
180:         if (self::length($s) > $maxLen) {
181:             $maxLen = $maxLen - self::length($append);
182:             if ($maxLen < 1) {
183:                 return $append;
184: 
185:             } elseif ($matches = self::match($s, '#^.{1,'.$maxLen.'}(?=[\s\x00-/:-@\[-`{-~])#us')) {
186:                 return $matches[0] . $append;
187: 
188:             } else {
189:                 return iconv_substr($s, 0, $maxLen, 'UTF-8') . $append;
190:             }
191:         }
192:         return $s;
193:     }
194: 
195: 
196: 
197:     /**
198:      * Indents the content from the left.
199:      * @param  string  UTF-8 encoding or 8-bit
200:      * @param  int
201:      * @param  string
202:      * @return string
203:      */
204:     public static function indent($s, $level = 1, $chars = "\t")
205:     {
206:         return $level < 1 ? $s : self::replace($s, '#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level));
207:     }
208: 
209: 
210: 
211:     /**
212:      * Convert to lower case.
213:      * @param  string  UTF-8 encoding
214:      * @return string
215:      */
216:     public static function lower($s)
217:     {
218:         return mb_strtolower($s, 'UTF-8');
219:     }
220: 
221: 
222: 
223:     /**
224:      * Convert to upper case.
225:      * @param  string  UTF-8 encoding
226:      * @return string
227:      */
228:     public static function upper($s)
229:     {
230:         return mb_strtoupper($s, 'UTF-8');
231:     }
232: 
233: 
234: 
235:     /**
236:      * Convert first character to upper case.
237:      * @param  string  UTF-8 encoding
238:      * @return string
239:      */
240:     public static function firstUpper($s)
241:     {
242:         return self::upper(mb_substr($s, 0, 1, 'UTF-8')) . mb_substr($s, 1, self::length($s), 'UTF-8');
243:     }
244: 
245: 
246: 
247:     /**
248:      * Capitalize string.
249:      * @param  string  UTF-8 encoding
250:      * @return string
251:      */
252:     public static function capitalize($s)
253:     {
254:         return mb_convert_case($s, MB_CASE_TITLE, 'UTF-8');
255:     }
256: 
257: 
258: 
259:     /**
260:      * Case-insensitive compares UTF-8 strings.
261:      * @param  string
262:      * @param  string
263:      * @param  int
264:      * @return bool
265:      */
266:     public static function compare($left, $right, $len = NULL)
267:     {
268:         if ($len < 0) {
269:             $left = iconv_substr($left, $len, -$len, 'UTF-8');
270:             $right = iconv_substr($right, $len, -$len, 'UTF-8');
271:         } elseif ($len !== NULL) {
272:             $left = iconv_substr($left, 0, $len, 'UTF-8');
273:             $right = iconv_substr($right, 0, $len, 'UTF-8');
274:         }
275:         return self::lower($left) === self::lower($right);
276:     }
277: 
278: 
279: 
280:     /**
281:      * Returns UTF-8 string length.
282:      * @param  string
283:      * @return int
284:      */
285:     public static function length($s)
286:     {
287:         return function_exists('mb_strlen') ? mb_strlen($s, 'UTF-8') : strlen(utf8_decode($s));
288:     }
289: 
290: 
291: 
292:     /**
293:      * Strips whitespace.
294:      * @param  string  UTF-8 encoding
295:      * @param  string
296:      * @return string
297:      */
298:     public static function trim($s, $charlist = " \t\n\r\0\x0B\xC2\xA0")
299:     {
300:         $charlist = preg_quote($charlist, '#');
301:         return self::replace($s, '#^['.$charlist.']+|['.$charlist.']+$#u', '');
302:     }
303: 
304: 
305: 
306:     /**
307:      * Pad a string to a certain length with another string.
308:      * @param  string  UTF-8 encoding
309:      * @param  int
310:      * @param  string
311:      * @return string
312:      */
313:     public static function padLeft($s, $length, $pad = ' ')
314:     {
315:         $length = max(0, $length - self::length($s));
316:         $padLen = self::length($pad);
317:         return str_repeat($pad, $length / $padLen) . iconv_substr($pad, 0, $length % $padLen, 'UTF-8') . $s;
318:     }
319: 
320: 
321: 
322:     /**
323:      * Pad a string to a certain length with another string.
324:      * @param  string  UTF-8 encoding
325:      * @param  int
326:      * @param  string
327:      * @return string
328:      */
329:     public static function padRight($s, $length, $pad = ' ')
330:     {
331:         $length = max(0, $length - self::length($s));
332:         $padLen = self::length($pad);
333:         return $s . str_repeat($pad, $length / $padLen) . iconv_substr($pad, 0, $length % $padLen, 'UTF-8');
334:     }
335: 
336: 
337: 
338:     /**
339:      * Generate random string.
340:      * @param  int
341:      * @param  string
342:      * @return string
343:      */
344:     public static function random($length = 10, $charlist = '0-9a-z')
345:     {
346:         $charlist = str_shuffle(preg_replace_callback('#.-.#', create_function('$m', '
347:             return implode(\'\', range($m[0][0], $m[0][2]));
348:         '), $charlist));
349:         $chLen = strlen($charlist);
350: 
351:         $s = '';
352:         for ($i = 0; $i < $length; $i++) {
353:             if ($i % 5 === 0) {
354:                 $rand = lcg_value();
355:                 $rand2 = microtime(TRUE);
356:             }
357:             $rand *= $chLen;
358:             $s .= $charlist[($rand + $rand2) % $chLen];
359:             $rand -= (int) $rand;
360:         }
361:         return $s;
362:     }
363: 
364: 
365: 
366:     /**
367:      * Splits string by a regular expression.
368:      * @param  string
369:      * @param  string
370:      * @param  int
371:      * @return array
372:      */
373:     public static function split($subject, $pattern, $flags = 0)
374:     {
375:         NDebugger::tryError();
376:         $res = preg_split($pattern, $subject, -1, $flags | PREG_SPLIT_DELIM_CAPTURE);
377:         self::catchPregError($pattern);
378:         return $res;
379:     }
380: 
381: 
382: 
383:     /**
384:      * Performs a regular expression match.
385:      * @param  string
386:      * @param  string
387:      * @param  int
388:      * @param  int
389:      * @return mixed
390:      */
391:     public static function match($subject, $pattern, $flags = 0, $offset = 0)
392:     {
393:         NDebugger::tryError();
394:         $res = preg_match($pattern, $subject, $m, $flags, $offset);
395:         self::catchPregError($pattern);
396:         if ($res) {
397:             return $m;
398:         }
399:     }
400: 
401: 
402: 
403:     /**
404:      * Performs a global regular expression match.
405:      * @param  string
406:      * @param  string
407:      * @param  int  (PREG_SET_ORDER is default)
408:      * @param  int
409:      * @return array
410:      */
411:     public static function matchAll($subject, $pattern, $flags = 0, $offset = 0)
412:     {
413:         NDebugger::tryError();
414:         $res = preg_match_all(
415:             $pattern, $subject, $m,
416:             ($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER),
417:             $offset
418:         );
419:         self::catchPregError($pattern);
420:         return $m;
421:     }
422: 
423: 
424: 
425:     /**
426:      * Perform a regular expression search and replace.
427:      * @param  string
428:      * @param  string|array
429:      * @param  string|callback
430:      * @param  int
431:      * @return string
432:      */
433:     public static function replace($subject, $pattern, $replacement = NULL, $limit = -1)
434:     {
435:         NDebugger::tryError();
436:         if (is_object($replacement) || is_array($replacement)) {
437:             if ($replacement instanceof NCallback) {
438:                 $replacement = $replacement->getNative();
439:             }
440:             if (!is_callable($replacement, FALSE, $textual)) {
441:                 NDebugger::catchError($foo);
442:                 throw new InvalidStateException("Callback '$textual' is not callable.");
443:             }
444:             $res = preg_replace_callback($pattern, $replacement, $subject, $limit);
445: 
446:             if (NDebugger::catchError($e)) { // compile error
447:                 $trace = $e->getTrace();
448:                 if (isset($trace[2]['class']) && $trace[2]['class'] === __CLASS__) {
449:                     throw new NRegexpException($e->getMessage() . " in pattern: $pattern");
450:                 }
451:             }
452: 
453:         } elseif (is_array($pattern)) {
454:             $res = preg_replace(array_keys($pattern), array_values($pattern), $subject, $limit);
455: 
456:         } else {
457:             $res = preg_replace($pattern, $replacement, $subject, $limit);
458:         }
459:         self::catchPregError($pattern);
460:         return $res;
461:     }
462: 
463: 
464: 
465:     /** @internal */
466:     public static function catchPregError($pattern)
467:     {
468:         if (NDebugger::catchError($e)) { // compile error
469:             throw new NRegexpException($e->getMessage() . " in pattern: $pattern");
470: 
471:         } elseif (preg_last_error()) { // run-time error
472:             static $messages = array(
473:                 PREG_INTERNAL_ERROR => 'Internal error',
474:                 PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted',
475:                 PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted',
476:                 PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data',
477:                 5 => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', // PREG_BAD_UTF8_OFFSET_ERROR
478:             );
479:             $code = preg_last_error();
480:             throw new NRegexpException((isset($messages[$code]) ? $messages[$code] : 'Unknown error') . " (pattern: $pattern)", $code);
481:         }
482:     }
483: 
484: 
485: 
486:     /**
487:      * Expands %placeholders% in string.
488:      * @param  string
489:      * @param  array
490:      * @param  bool
491:      * @return mixed
492:      * @throws InvalidArgumentException
493:      */
494:     public static function expand($s, array $params, $recursive = FALSE)
495:     {
496:         $parts = preg_split('#%([\w.-]*)%#i', $s, -1, PREG_SPLIT_DELIM_CAPTURE);
497:         $res = '';
498:         foreach ($parts as $n => $part) {
499:             if ($n % 2 === 0) {
500:                 $res .= $part;
501: 
502:             } elseif ($part === '') {
503:                 $res .= '%';
504: 
505:             } elseif (isset($recursive[$part])) {
506:                 throw new InvalidArgumentException('Circular reference detected for variables: ' . implode(', ', array_keys($recursive)) . '.');
507: 
508:             } else {
509:                 $val = NArrays::get($params, explode('.', $part));
510:                 if ($recursive && is_string($val)) {
511:                     $val = self::expand($val, $params, (is_array($recursive) ? $recursive : array()) + array($part => 1));
512:                 }
513:                 if (strlen($part) + 2 === strlen($s)) {
514:                     return $val;
515:                 }
516:                 if (!is_scalar($val)) {
517:                     throw new InvalidArgumentException("Unable to concatenate non-scalar parameter '$part' into '$s'.");
518:                 }
519:                 $res .= $val;
520:             }
521:         }
522:         return $res;
523:     }
524: 
525: }
526: 
527: 
528: 
529: /**
530:  * The exception that indicates error of the last Regexp execution.
531:  * @package Nette\Utils
532:  */
533: class NRegexpException extends Exception
534: {
535: }
536: 
Nette Framework 2.0beta1 (for PHP 5.2) API API documentation generated by ApiGen 2.3.0