Namespaces

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

Classes

  • Arrays
  • Finder
  • Html
  • Json
  • LimitedScope
  • MimeTypeDetector
  • Neon
  • NeonEntity
  • Paginator
  • Strings
  • Validators

Exceptions

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