Permalink
Browse files

Properly handle escaping of non-special characters and blackslashes [#14

]
  • Loading branch information...
1 parent 0c96c30 commit c93f47593536efd794d2c0944847fc1f1b7513a9 @jmalloc jmalloc committed Jan 24, 2013
View
50 lib/Icecave/Chrono/Format/DefaultFormatter.php
@@ -31,7 +31,11 @@ public function escape($string)
{
$this->typeCheck->escape(func_get_args());
- return preg_replace(self::SPECIAL_CHARS, '\\\\$0', $string);
+ return preg_replace(
+ '/(?<!\\\\)[' . preg_quote(self::SPECIAL_CHARS, '/') . ']/',
+ '\\\\$0',
+ $string
+ );
}
/**
@@ -192,7 +196,7 @@ public static function instance()
}
/**
- * @param string $formatSpecifier
+ * @param string $formatSpecifier
* @param callable $callback
*
* @return string
@@ -201,23 +205,39 @@ protected function replace($formatSpecifier, $callback)
{
$this->typeCheck->replace(func_get_args());
- $string = preg_replace_callback(
- self::SPECIAL_CHARS,
- function (array $match) use ($callback) {
- $result = $callback($match[0]);
- if (null === $result) {
- return $match[0];
+ $length = strlen($formatSpecifier);
+ $result = '';
+ $escaped = false;
+
+ for ($index = 0; $index < $length; ++$index) {
+ $char = $formatSpecifier[$index];
+
+ if ($escaped) {
+ $result .= $char;
+ $escaped = false;
+ } elseif ('\\' === $char) {
+ $escaped = true;
+ } elseif (false === strpos(self::SPECIAL_CHARS, $char)) {
+ $result .= $char;
+ } else {
+ $value = $callback($char);
+ if (null === $value) {
+ $result .= $char;
+ } else {
+ $result .= $value;
}
- return $result;
- },
- $formatSpecifier
- );
+ }
+ }
+
+ // Last character was escape character ...
+ if ($escaped) {
+ $result .= '\\';
+ }
- return preg_replace(self::ESCAPED_CHARS, '$1', $string);
+ return $result;
}
- const SPECIAL_CHARS = '/(?<!\\\\)[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/';
- const ESCAPED_CHARS = '/\\\\([dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU])/';
+ const SPECIAL_CHARS = 'dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU';
private static $instance;
private $typeCheck;
View
24 test/suite/Icecave/Chrono/Format/DefaultFormatterTest.php
@@ -38,6 +38,30 @@ public function testEscapingIsHonoured()
// $this->assertSame($this->_specialChars, $this->_formatter->formatTimeZone($this->_timeZone, $this->_specialChars));
}
+ public function testEscapingOfNonSpecialCharacters()
+ {
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatDate($this->_date, $this->_specialChars));
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatTime($this->_time, $this->_specialChars));
+ $this->assertSame('X', $this->_formatter->formatDateTime($this->_dateTime, '\X'));
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatTimeZone($this->_timeZone, $this->_specialChars));
+ }
+
+ public function testEscapingOfBackslash()
+ {
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatDate($this->_date, $this->_specialChars));
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatTime($this->_time, $this->_specialChars));
+ $this->assertSame('\X', $this->_formatter->formatDateTime($this->_dateTime, '\\\\X'));
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatTimeZone($this->_timeZone, $this->_specialChars));
+ }
+
+ public function testEscapingBackslashAtEnd()
+ {
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatDate($this->_date, $this->_specialChars));
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatTime($this->_time, $this->_specialChars));
+ $this->assertSame('X\\', $this->_formatter->formatDateTime($this->_dateTime, 'X\\'));
+ // $this->assertSame($this->_specialChars, $this->_formatter->formatTimeZone($this->_timeZone, $this->_specialChars));
+ }
+
// /**
// * @dataProvider dateFormats
// */

0 comments on commit c93f475

Please sign in to comment.