AbstractStringWrapper.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Stdlib\StringWrapper;
  10. use Zend\Stdlib\Exception;
  11. use Zend\Stdlib\StringUtils;
  12. abstract class AbstractStringWrapper implements StringWrapperInterface
  13. {
  14. /**
  15. * The character encoding working on
  16. * @var string|null
  17. */
  18. protected $encoding = 'UTF-8';
  19. /**
  20. * An optionally character encoding to convert to
  21. * @var string|null
  22. */
  23. protected $convertEncoding;
  24. /**
  25. * Check if the given character encoding is supported by this wrapper
  26. * and the character encoding to convert to is also supported.
  27. *
  28. * @param string $encoding
  29. * @param string|null $convertEncoding
  30. * @return bool
  31. */
  32. public static function isSupported($encoding, $convertEncoding = null)
  33. {
  34. $supportedEncodings = static::getSupportedEncodings();
  35. if (!in_array(strtoupper($encoding), $supportedEncodings)) {
  36. return false;
  37. }
  38. if ($convertEncoding !== null && !in_array(strtoupper($convertEncoding), $supportedEncodings)) {
  39. return false;
  40. }
  41. return true;
  42. }
  43. /**
  44. * Set character encoding working with and convert to
  45. *
  46. * @param string $encoding The character encoding to work with
  47. * @param string|null $convertEncoding The character encoding to convert to
  48. * @return StringWrapperInterface
  49. */
  50. public function setEncoding($encoding, $convertEncoding = null)
  51. {
  52. $supportedEncodings = static::getSupportedEncodings();
  53. $encodingUpper = strtoupper($encoding);
  54. if (!in_array($encodingUpper, $supportedEncodings)) {
  55. throw new Exception\InvalidArgumentException(
  56. 'Wrapper doesn\'t support character encoding "' . $encoding . '"'
  57. );
  58. }
  59. if ($convertEncoding !== null) {
  60. $convertEncodingUpper = strtoupper($convertEncoding);
  61. if (!in_array($convertEncodingUpper, $supportedEncodings)) {
  62. throw new Exception\InvalidArgumentException(
  63. 'Wrapper doesn\'t support character encoding "' . $convertEncoding . '"'
  64. );
  65. }
  66. $this->convertEncoding = $convertEncodingUpper;
  67. } else {
  68. $this->convertEncoding = null;
  69. }
  70. $this->encoding = $encodingUpper;
  71. return $this;
  72. }
  73. /**
  74. * Get the defined character encoding to work with
  75. *
  76. * @return string
  77. * @throws Exception\LogicException If no encoding was defined
  78. */
  79. public function getEncoding()
  80. {
  81. return $this->encoding;
  82. }
  83. /**
  84. * Get the defined character encoding to convert to
  85. *
  86. * @return string|null
  87. */
  88. public function getConvertEncoding()
  89. {
  90. return $this->convertEncoding;
  91. }
  92. /**
  93. * Convert a string from defined character encoding to the defined convert encoding
  94. *
  95. * @param string $str
  96. * @param bool $reverse
  97. * @return string|false
  98. */
  99. public function convert($str, $reverse = false)
  100. {
  101. $encoding = $this->getEncoding();
  102. $convertEncoding = $this->getConvertEncoding();
  103. if ($convertEncoding === null) {
  104. throw new Exception\LogicException(
  105. 'No convert encoding defined'
  106. );
  107. }
  108. if ($encoding === $convertEncoding) {
  109. return $str;
  110. }
  111. $from = $reverse ? $convertEncoding : $encoding;
  112. $to = $reverse ? $encoding : $convertEncoding;
  113. throw new Exception\RuntimeException(sprintf(
  114. 'Converting from "%s" to "%s" isn\'t supported by this string wrapper',
  115. $from,
  116. $to
  117. ));
  118. }
  119. /**
  120. * Wraps a string to a given number of characters
  121. *
  122. * @param string $string
  123. * @param int $width
  124. * @param string $break
  125. * @param bool $cut
  126. * @return string|false
  127. */
  128. public function wordWrap($string, $width = 75, $break = "\n", $cut = false)
  129. {
  130. $string = (string) $string;
  131. if ($string === '') {
  132. return '';
  133. }
  134. $break = (string) $break;
  135. if ($break === '') {
  136. throw new Exception\InvalidArgumentException('Break string cannot be empty');
  137. }
  138. $width = (int) $width;
  139. if ($width === 0 && $cut) {
  140. throw new Exception\InvalidArgumentException('Cannot force cut when width is zero');
  141. }
  142. if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
  143. return wordwrap($string, $width, $break, $cut);
  144. }
  145. $stringWidth = $this->strlen($string);
  146. $breakWidth = $this->strlen($break);
  147. $result = '';
  148. $lastStart = $lastSpace = 0;
  149. for ($current = 0; $current < $stringWidth; $current++) {
  150. $char = $this->substr($string, $current, 1);
  151. $possibleBreak = $char;
  152. if ($breakWidth !== 1) {
  153. $possibleBreak = $this->substr($string, $current, $breakWidth);
  154. }
  155. if ($possibleBreak === $break) {
  156. $result .= $this->substr($string, $lastStart, $current - $lastStart + $breakWidth);
  157. $current += $breakWidth - 1;
  158. $lastStart = $lastSpace = $current + 1;
  159. continue;
  160. }
  161. if ($char === ' ') {
  162. if ($current - $lastStart >= $width) {
  163. $result .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
  164. $lastStart = $current + 1;
  165. }
  166. $lastSpace = $current;
  167. continue;
  168. }
  169. if ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
  170. $result .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
  171. $lastStart = $lastSpace = $current;
  172. continue;
  173. }
  174. if ($current - $lastStart >= $width && $lastStart < $lastSpace) {
  175. $result .= $this->substr($string, $lastStart, $lastSpace - $lastStart) . $break;
  176. $lastStart = $lastSpace = $lastSpace + 1;
  177. continue;
  178. }
  179. }
  180. if ($lastStart !== $current) {
  181. $result .= $this->substr($string, $lastStart, $current - $lastStart);
  182. }
  183. return $result;
  184. }
  185. /**
  186. * Pad a string to a certain length with another string
  187. *
  188. * @param string $input
  189. * @param int $padLength
  190. * @param string $padString
  191. * @param int $padType
  192. * @return string
  193. */
  194. public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT)
  195. {
  196. if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
  197. return str_pad($input, $padLength, $padString, $padType);
  198. }
  199. $lengthOfPadding = $padLength - $this->strlen($input);
  200. if ($lengthOfPadding <= 0) {
  201. return $input;
  202. }
  203. $padStringLength = $this->strlen($padString);
  204. if ($padStringLength === 0) {
  205. return $input;
  206. }
  207. $repeatCount = floor($lengthOfPadding / $padStringLength);
  208. if ($padType === STR_PAD_BOTH) {
  209. $repeatCountLeft = $repeatCountRight = ($repeatCount - $repeatCount % 2) / 2;
  210. $lastStringLength = $lengthOfPadding - 2 * $repeatCountLeft * $padStringLength;
  211. $lastStringLeftLength = $lastStringRightLength = floor($lastStringLength / 2);
  212. $lastStringRightLength += $lastStringLength % 2;
  213. $lastStringLeft = $this->substr($padString, 0, $lastStringLeftLength);
  214. $lastStringRight = $this->substr($padString, 0, $lastStringRightLength);
  215. return str_repeat($padString, $repeatCountLeft) . $lastStringLeft
  216. . $input
  217. . str_repeat($padString, $repeatCountRight) . $lastStringRight;
  218. }
  219. $lastString = $this->substr($padString, 0, $lengthOfPadding % $padStringLength);
  220. if ($padType === STR_PAD_LEFT) {
  221. return str_repeat($padString, $repeatCount) . $lastString . $input;
  222. }
  223. return $input . str_repeat($padString, $repeatCount) . $lastString;
  224. }
  225. }