For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

819 lines
27 KiB

  1. <?php
  2. /**
  3. * PHPExcel_Shared_String
  4. *
  5. * Copyright (c) 2006 - 2015 PHPExcel
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category PHPExcel
  22. * @package PHPExcel_Shared
  23. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version ##VERSION##, ##DATE##
  26. */
  27. class PHPExcel_Shared_String
  28. {
  29. /** Constants */
  30. /** Regular Expressions */
  31. // Fraction
  32. const STRING_REGEXP_FRACTION = '(-?)(\d+)\s+(\d+\/\d+)';
  33. /**
  34. * Control characters array
  35. *
  36. * @var string[]
  37. */
  38. private static $controlCharacters = array();
  39. /**
  40. * SYLK Characters array
  41. *
  42. * $var array
  43. */
  44. private static $SYLKCharacters = array();
  45. /**
  46. * Decimal separator
  47. *
  48. * @var string
  49. */
  50. private static $decimalSeparator;
  51. /**
  52. * Thousands separator
  53. *
  54. * @var string
  55. */
  56. private static $thousandsSeparator;
  57. /**
  58. * Currency code
  59. *
  60. * @var string
  61. */
  62. private static $currencyCode;
  63. /**
  64. * Is mbstring extension avalable?
  65. *
  66. * @var boolean
  67. */
  68. private static $isMbstringEnabled;
  69. /**
  70. * Is iconv extension avalable?
  71. *
  72. * @var boolean
  73. */
  74. private static $isIconvEnabled;
  75. /**
  76. * Build control characters array
  77. */
  78. private static function buildControlCharacters()
  79. {
  80. for ($i = 0; $i <= 31; ++$i) {
  81. if ($i != 9 && $i != 10 && $i != 13) {
  82. $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
  83. $replace = chr($i);
  84. self::$controlCharacters[$find] = $replace;
  85. }
  86. }
  87. }
  88. /**
  89. * Build SYLK characters array
  90. */
  91. private static function buildSYLKCharacters()
  92. {
  93. self::$SYLKCharacters = array(
  94. "\x1B 0" => chr(0),
  95. "\x1B 1" => chr(1),
  96. "\x1B 2" => chr(2),
  97. "\x1B 3" => chr(3),
  98. "\x1B 4" => chr(4),
  99. "\x1B 5" => chr(5),
  100. "\x1B 6" => chr(6),
  101. "\x1B 7" => chr(7),
  102. "\x1B 8" => chr(8),
  103. "\x1B 9" => chr(9),
  104. "\x1B :" => chr(10),
  105. "\x1B ;" => chr(11),
  106. "\x1B <" => chr(12),
  107. "\x1B :" => chr(13),
  108. "\x1B >" => chr(14),
  109. "\x1B ?" => chr(15),
  110. "\x1B!0" => chr(16),
  111. "\x1B!1" => chr(17),
  112. "\x1B!2" => chr(18),
  113. "\x1B!3" => chr(19),
  114. "\x1B!4" => chr(20),
  115. "\x1B!5" => chr(21),
  116. "\x1B!6" => chr(22),
  117. "\x1B!7" => chr(23),
  118. "\x1B!8" => chr(24),
  119. "\x1B!9" => chr(25),
  120. "\x1B!:" => chr(26),
  121. "\x1B!;" => chr(27),
  122. "\x1B!<" => chr(28),
  123. "\x1B!=" => chr(29),
  124. "\x1B!>" => chr(30),
  125. "\x1B!?" => chr(31),
  126. "\x1B'?" => chr(127),
  127. "\x1B(0" => '€', // 128 in CP1252
  128. "\x1B(2" => '‚', // 130 in CP1252
  129. "\x1B(3" => 'ƒ', // 131 in CP1252
  130. "\x1B(4" => '„', // 132 in CP1252
  131. "\x1B(5" => '…', // 133 in CP1252
  132. "\x1B(6" => '†', // 134 in CP1252
  133. "\x1B(7" => '‡', // 135 in CP1252
  134. "\x1B(8" => 'ˆ', // 136 in CP1252
  135. "\x1B(9" => '‰', // 137 in CP1252
  136. "\x1B(:" => 'Š', // 138 in CP1252
  137. "\x1B(;" => '‹', // 139 in CP1252
  138. "\x1BNj" => 'Œ', // 140 in CP1252
  139. "\x1B(>" => 'Ž', // 142 in CP1252
  140. "\x1B)1" => '‘', // 145 in CP1252
  141. "\x1B)2" => '’', // 146 in CP1252
  142. "\x1B)3" => '“', // 147 in CP1252
  143. "\x1B)4" => '”', // 148 in CP1252
  144. "\x1B)5" => '•', // 149 in CP1252
  145. "\x1B)6" => '–', // 150 in CP1252
  146. "\x1B)7" => '—', // 151 in CP1252
  147. "\x1B)8" => '˜', // 152 in CP1252
  148. "\x1B)9" => '™', // 153 in CP1252
  149. "\x1B):" => 'š', // 154 in CP1252
  150. "\x1B);" => '›', // 155 in CP1252
  151. "\x1BNz" => 'œ', // 156 in CP1252
  152. "\x1B)>" => 'ž', // 158 in CP1252
  153. "\x1B)?" => 'Ÿ', // 159 in CP1252
  154. "\x1B*0" => ' ', // 160 in CP1252
  155. "\x1BN!" => '¡', // 161 in CP1252
  156. "\x1BN\"" => '¢', // 162 in CP1252
  157. "\x1BN#" => '£', // 163 in CP1252
  158. "\x1BN(" => '¤', // 164 in CP1252
  159. "\x1BN%" => '¥', // 165 in CP1252
  160. "\x1B*6" => '¦', // 166 in CP1252
  161. "\x1BN'" => '§', // 167 in CP1252
  162. "\x1BNH " => '¨', // 168 in CP1252
  163. "\x1BNS" => '©', // 169 in CP1252
  164. "\x1BNc" => 'ª', // 170 in CP1252
  165. "\x1BN+" => '«', // 171 in CP1252
  166. "\x1B*<" => '¬', // 172 in CP1252
  167. "\x1B*=" => '­', // 173 in CP1252
  168. "\x1BNR" => '®', // 174 in CP1252
  169. "\x1B*?" => '¯', // 175 in CP1252
  170. "\x1BN0" => '°', // 176 in CP1252
  171. "\x1BN1" => '±', // 177 in CP1252
  172. "\x1BN2" => '²', // 178 in CP1252
  173. "\x1BN3" => '³', // 179 in CP1252
  174. "\x1BNB " => '´', // 180 in CP1252
  175. "\x1BN5" => 'µ', // 181 in CP1252
  176. "\x1BN6" => '¶', // 182 in CP1252
  177. "\x1BN7" => '·', // 183 in CP1252
  178. "\x1B+8" => '¸', // 184 in CP1252
  179. "\x1BNQ" => '¹', // 185 in CP1252
  180. "\x1BNk" => 'º', // 186 in CP1252
  181. "\x1BN;" => '»', // 187 in CP1252
  182. "\x1BN<" => '¼', // 188 in CP1252
  183. "\x1BN=" => '½', // 189 in CP1252
  184. "\x1BN>" => '¾', // 190 in CP1252
  185. "\x1BN?" => '¿', // 191 in CP1252
  186. "\x1BNAA" => 'À', // 192 in CP1252
  187. "\x1BNBA" => 'Á', // 193 in CP1252
  188. "\x1BNCA" => 'Â', // 194 in CP1252
  189. "\x1BNDA" => 'Ã', // 195 in CP1252
  190. "\x1BNHA" => 'Ä', // 196 in CP1252
  191. "\x1BNJA" => 'Å', // 197 in CP1252
  192. "\x1BNa" => 'Æ', // 198 in CP1252
  193. "\x1BNKC" => 'Ç', // 199 in CP1252
  194. "\x1BNAE" => 'È', // 200 in CP1252
  195. "\x1BNBE" => 'É', // 201 in CP1252
  196. "\x1BNCE" => 'Ê', // 202 in CP1252
  197. "\x1BNHE" => 'Ë', // 203 in CP1252
  198. "\x1BNAI" => 'Ì', // 204 in CP1252
  199. "\x1BNBI" => 'Í', // 205 in CP1252
  200. "\x1BNCI" => 'Î', // 206 in CP1252
  201. "\x1BNHI" => 'Ï', // 207 in CP1252
  202. "\x1BNb" => 'Ð', // 208 in CP1252
  203. "\x1BNDN" => 'Ñ', // 209 in CP1252
  204. "\x1BNAO" => 'Ò', // 210 in CP1252
  205. "\x1BNBO" => 'Ó', // 211 in CP1252
  206. "\x1BNCO" => 'Ô', // 212 in CP1252
  207. "\x1BNDO" => 'Õ', // 213 in CP1252
  208. "\x1BNHO" => 'Ö', // 214 in CP1252
  209. "\x1B-7" => '×', // 215 in CP1252
  210. "\x1BNi" => 'Ø', // 216 in CP1252
  211. "\x1BNAU" => 'Ù', // 217 in CP1252
  212. "\x1BNBU" => 'Ú', // 218 in CP1252
  213. "\x1BNCU" => 'Û', // 219 in CP1252
  214. "\x1BNHU" => 'Ü', // 220 in CP1252
  215. "\x1B-=" => 'Ý', // 221 in CP1252
  216. "\x1BNl" => 'Þ', // 222 in CP1252
  217. "\x1BN{" => 'ß', // 223 in CP1252
  218. "\x1BNAa" => 'à', // 224 in CP1252
  219. "\x1BNBa" => 'á', // 225 in CP1252
  220. "\x1BNCa" => 'â', // 226 in CP1252
  221. "\x1BNDa" => 'ã', // 227 in CP1252
  222. "\x1BNHa" => 'ä', // 228 in CP1252
  223. "\x1BNJa" => 'å', // 229 in CP1252
  224. "\x1BNq" => 'æ', // 230 in CP1252
  225. "\x1BNKc" => 'ç', // 231 in CP1252
  226. "\x1BNAe" => 'è', // 232 in CP1252
  227. "\x1BNBe" => 'é', // 233 in CP1252
  228. "\x1BNCe" => 'ê', // 234 in CP1252
  229. "\x1BNHe" => 'ë', // 235 in CP1252
  230. "\x1BNAi" => 'ì', // 236 in CP1252
  231. "\x1BNBi" => 'í', // 237 in CP1252
  232. "\x1BNCi" => 'î', // 238 in CP1252
  233. "\x1BNHi" => 'ï', // 239 in CP1252
  234. "\x1BNs" => 'ð', // 240 in CP1252
  235. "\x1BNDn" => 'ñ', // 241 in CP1252
  236. "\x1BNAo" => 'ò', // 242 in CP1252
  237. "\x1BNBo" => 'ó', // 243 in CP1252
  238. "\x1BNCo" => 'ô', // 244 in CP1252
  239. "\x1BNDo" => 'õ', // 245 in CP1252
  240. "\x1BNHo" => 'ö', // 246 in CP1252
  241. "\x1B/7" => '÷', // 247 in CP1252
  242. "\x1BNy" => 'ø', // 248 in CP1252
  243. "\x1BNAu" => 'ù', // 249 in CP1252
  244. "\x1BNBu" => 'ú', // 250 in CP1252
  245. "\x1BNCu" => 'û', // 251 in CP1252
  246. "\x1BNHu" => 'ü', // 252 in CP1252
  247. "\x1B/=" => 'ý', // 253 in CP1252
  248. "\x1BN|" => 'þ', // 254 in CP1252
  249. "\x1BNHy" => 'ÿ', // 255 in CP1252
  250. );
  251. }
  252. /**
  253. * Get whether mbstring extension is available
  254. *
  255. * @return boolean
  256. */
  257. public static function getIsMbstringEnabled()
  258. {
  259. if (isset(self::$isMbstringEnabled)) {
  260. return self::$isMbstringEnabled;
  261. }
  262. self::$isMbstringEnabled = function_exists('mb_convert_encoding') ?
  263. true : false;
  264. return self::$isMbstringEnabled;
  265. }
  266. /**
  267. * Get whether iconv extension is available
  268. *
  269. * @return boolean
  270. */
  271. public static function getIsIconvEnabled()
  272. {
  273. if (isset(self::$isIconvEnabled)) {
  274. return self::$isIconvEnabled;
  275. }
  276. // Fail if iconv doesn't exist
  277. if (!function_exists('iconv')) {
  278. self::$isIconvEnabled = false;
  279. return false;
  280. }
  281. // Sometimes iconv is not working, and e.g. iconv('UTF-8', 'UTF-16LE', 'x') just returns false,
  282. if (!@iconv('UTF-8', 'UTF-16LE', 'x')) {
  283. self::$isIconvEnabled = false;
  284. return false;
  285. }
  286. // Sometimes iconv_substr('A', 0, 1, 'UTF-8') just returns false in PHP 5.2.0
  287. // we cannot use iconv in that case either (http://bugs.php.net/bug.php?id=37773)
  288. if (!@iconv_substr('A', 0, 1, 'UTF-8')) {
  289. self::$isIconvEnabled = false;
  290. return false;
  291. }
  292. // CUSTOM: IBM AIX iconv() does not work
  293. if (defined('PHP_OS') && @stristr(PHP_OS, 'AIX') && defined('ICONV_IMPL') && (@strcasecmp(ICONV_IMPL, 'unknown') == 0) && defined('ICONV_VERSION') && (@strcasecmp(ICONV_VERSION, 'unknown') == 0)) {
  294. self::$isIconvEnabled = false;
  295. return false;
  296. }
  297. // If we reach here no problems were detected with iconv
  298. self::$isIconvEnabled = true;
  299. return true;
  300. }
  301. public static function buildCharacterSets()
  302. {
  303. if (empty(self::$controlCharacters)) {
  304. self::buildControlCharacters();
  305. }
  306. if (empty(self::$SYLKCharacters)) {
  307. self::buildSYLKCharacters();
  308. }
  309. }
  310. /**
  311. * Convert from OpenXML escaped control character to PHP control character
  312. *
  313. * Excel 2007 team:
  314. * ----------------
  315. * That's correct, control characters are stored directly in the shared-strings table.
  316. * We do encode characters that cannot be represented in XML using the following escape sequence:
  317. * _xHHHH_ where H represents a hexadecimal character in the character's value...
  318. * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
  319. * element or in the shared string <t> element.
  320. *
  321. * @param string $value Value to unescape
  322. * @return string
  323. */
  324. public static function ControlCharacterOOXML2PHP($value = '')
  325. {
  326. return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
  327. }
  328. /**
  329. * Convert from PHP control character to OpenXML escaped control character
  330. *
  331. * Excel 2007 team:
  332. * ----------------
  333. * That's correct, control characters are stored directly in the shared-strings table.
  334. * We do encode characters that cannot be represented in XML using the following escape sequence:
  335. * _xHHHH_ where H represents a hexadecimal character in the character's value...
  336. * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
  337. * element or in the shared string <t> element.
  338. *
  339. * @param string $value Value to escape
  340. * @return string
  341. */
  342. public static function ControlCharacterPHP2OOXML($value = '')
  343. {
  344. return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);
  345. }
  346. /**
  347. * Try to sanitize UTF8, stripping invalid byte sequences. Not perfect. Does not surrogate characters.
  348. *
  349. * @param string $value
  350. * @return string
  351. */
  352. public static function SanitizeUTF8($value)
  353. {
  354. if (self::getIsIconvEnabled()) {
  355. $value = @iconv('UTF-8', 'UTF-8', $value);
  356. return $value;
  357. }
  358. if (self::getIsMbstringEnabled()) {
  359. $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
  360. return $value;
  361. }
  362. // else, no conversion
  363. return $value;
  364. }
  365. /**
  366. * Check if a string contains UTF8 data
  367. *
  368. * @param string $value
  369. * @return boolean
  370. */
  371. public static function IsUTF8($value = '')
  372. {
  373. return $value === '' || preg_match('/^./su', $value) === 1;
  374. }
  375. /**
  376. * Formats a numeric value as a string for output in various output writers forcing
  377. * point as decimal separator in case locale is other than English.
  378. *
  379. * @param mixed $value
  380. * @return string
  381. */
  382. public static function FormatNumber($value)
  383. {
  384. if (is_float($value)) {
  385. return str_replace(',', '.', $value);
  386. }
  387. return (string) $value;
  388. }
  389. /**
  390. * Converts a UTF-8 string into BIFF8 Unicode string data (8-bit string length)
  391. * Writes the string using uncompressed notation, no rich text, no Asian phonetics
  392. * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
  393. * although this will give wrong results for non-ASCII strings
  394. * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3
  395. *
  396. * @param string $value UTF-8 encoded string
  397. * @param mixed[] $arrcRuns Details of rich text runs in $value
  398. * @return string
  399. */
  400. public static function UTF8toBIFF8UnicodeShort($value, $arrcRuns = array())
  401. {
  402. // character count
  403. $ln = self::CountCharacters($value, 'UTF-8');
  404. // option flags
  405. if (empty($arrcRuns)) {
  406. $opt = (self::getIsIconvEnabled() || self::getIsMbstringEnabled()) ?
  407. 0x0001 : 0x0000;
  408. $data = pack('CC', $ln, $opt);
  409. // characters
  410. $data .= self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
  411. } else {
  412. $data = pack('vC', $ln, 0x09);
  413. $data .= pack('v', count($arrcRuns));
  414. // characters
  415. $data .= self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
  416. foreach ($arrcRuns as $cRun) {
  417. $data .= pack('v', $cRun['strlen']);
  418. $data .= pack('v', $cRun['fontidx']);
  419. }
  420. }
  421. return $data;
  422. }
  423. /**
  424. * Converts a UTF-8 string into BIFF8 Unicode string data (16-bit string length)
  425. * Writes the string using uncompressed notation, no rich text, no Asian phonetics
  426. * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
  427. * although this will give wrong results for non-ASCII strings
  428. * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3
  429. *
  430. * @param string $value UTF-8 encoded string
  431. * @return string
  432. */
  433. public static function UTF8toBIFF8UnicodeLong($value)
  434. {
  435. // character count
  436. $ln = self::CountCharacters($value, 'UTF-8');
  437. // option flags
  438. $opt = (self::getIsIconvEnabled() || self::getIsMbstringEnabled()) ?
  439. 0x0001 : 0x0000;
  440. // characters
  441. $chars = self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
  442. $data = pack('vC', $ln, $opt) . $chars;
  443. return $data;
  444. }
  445. /**
  446. * Convert string from one encoding to another. First try mbstring, then iconv, finally strlen
  447. *
  448. * @param string $value
  449. * @param string $to Encoding to convert to, e.g. 'UTF-8'
  450. * @param string $from Encoding to convert from, e.g. 'UTF-16LE'
  451. * @return string
  452. */
  453. public static function ConvertEncoding($value, $to, $from)
  454. {
  455. if (self::getIsIconvEnabled()) {
  456. return iconv($from, $to, $value);
  457. }
  458. if (self::getIsMbstringEnabled()) {
  459. return mb_convert_encoding($value, $to, $from);
  460. }
  461. if ($from == 'UTF-16LE') {
  462. return self::utf16_decode($value, false);
  463. } elseif ($from == 'UTF-16BE') {
  464. return self::utf16_decode($value);
  465. }
  466. // else, no conversion
  467. return $value;
  468. }
  469. /**
  470. * Decode UTF-16 encoded strings.
  471. *
  472. * Can handle both BOM'ed data and un-BOM'ed data.
  473. * Assumes Big-Endian byte order if no BOM is available.
  474. * This function was taken from http://php.net/manual/en/function.utf8-decode.php
  475. * and $bom_be parameter added.
  476. *
  477. * @param string $str UTF-16 encoded data to decode.
  478. * @return string UTF-8 / ISO encoded data.
  479. * @access public
  480. * @version 0.2 / 2010-05-13
  481. * @author Rasmus Andersson {@link http://rasmusandersson.se/}
  482. * @author vadik56
  483. */
  484. public static function utf16_decode($str, $bom_be = true)
  485. {
  486. if (strlen($str) < 2) {
  487. return $str;
  488. }
  489. $c0 = ord($str[0]);
  490. $c1 = ord($str[1]);
  491. if ($c0 == 0xfe && $c1 == 0xff) {
  492. $str = substr($str, 2);
  493. } elseif ($c0 == 0xff && $c1 == 0xfe) {
  494. $str = substr($str, 2);
  495. $bom_be = false;
  496. }
  497. $len = strlen($str);
  498. $newstr = '';
  499. for ($i=0; $i<$len; $i+=2) {
  500. if ($bom_be) {
  501. $val = ord($str[$i]) << 4;
  502. $val += ord($str[$i+1]);
  503. } else {
  504. $val = ord($str[$i+1]) << 4;
  505. $val += ord($str[$i]);
  506. }
  507. $newstr .= ($val == 0x228) ? "\n" : chr($val);
  508. }
  509. return $newstr;
  510. }
  511. /**
  512. * Get character count. First try mbstring, then iconv, finally strlen
  513. *
  514. * @param string $value
  515. * @param string $enc Encoding
  516. * @return int Character count
  517. */
  518. public static function CountCharacters($value, $enc = 'UTF-8')
  519. {
  520. if (self::getIsMbstringEnabled()) {
  521. return mb_strlen($value, $enc);
  522. }
  523. if (self::getIsIconvEnabled()) {
  524. return iconv_strlen($value, $enc);
  525. }
  526. // else strlen
  527. return strlen($value);
  528. }
  529. /**
  530. * Get a substring of a UTF-8 encoded string. First try mbstring, then iconv, finally strlen
  531. *
  532. * @param string $pValue UTF-8 encoded string
  533. * @param int $pStart Start offset
  534. * @param int $pLength Maximum number of characters in substring
  535. * @return string
  536. */
  537. public static function Substring($pValue = '', $pStart = 0, $pLength = 0)
  538. {
  539. if (self::getIsMbstringEnabled()) {
  540. return mb_substr($pValue, $pStart, $pLength, 'UTF-8');
  541. }
  542. if (self::getIsIconvEnabled()) {
  543. return iconv_substr($pValue, $pStart, $pLength, 'UTF-8');
  544. }
  545. // else substr
  546. return substr($pValue, $pStart, $pLength);
  547. }
  548. /**
  549. * Convert a UTF-8 encoded string to upper case
  550. *
  551. * @param string $pValue UTF-8 encoded string
  552. * @return string
  553. */
  554. public static function StrToUpper($pValue = '')
  555. {
  556. if (function_exists('mb_convert_case')) {
  557. return mb_convert_case($pValue, MB_CASE_UPPER, "UTF-8");
  558. }
  559. return strtoupper($pValue);
  560. }
  561. /**
  562. * Convert a UTF-8 encoded string to lower case
  563. *
  564. * @param string $pValue UTF-8 encoded string
  565. * @return string
  566. */
  567. public static function StrToLower($pValue = '')
  568. {
  569. if (function_exists('mb_convert_case')) {
  570. return mb_convert_case($pValue, MB_CASE_LOWER, "UTF-8");
  571. }
  572. return strtolower($pValue);
  573. }
  574. /**
  575. * Convert a UTF-8 encoded string to title/proper case
  576. * (uppercase every first character in each word, lower case all other characters)
  577. *
  578. * @param string $pValue UTF-8 encoded string
  579. * @return string
  580. */
  581. public static function StrToTitle($pValue = '')
  582. {
  583. if (function_exists('mb_convert_case')) {
  584. return mb_convert_case($pValue, MB_CASE_TITLE, "UTF-8");
  585. }
  586. return ucwords($pValue);
  587. }
  588. public static function mb_is_upper($char)
  589. {
  590. return mb_strtolower($char, "UTF-8") != $char;
  591. }
  592. public static function mb_str_split($string)
  593. {
  594. # Split at all position not after the start: ^
  595. # and not before the end: $
  596. return preg_split('/(?<!^)(?!$)/u', $string);
  597. }
  598. /**
  599. * Reverse the case of a string, so that all uppercase characters become lowercase
  600. * and all lowercase characters become uppercase
  601. *
  602. * @param string $pValue UTF-8 encoded string
  603. * @return string
  604. */
  605. public static function StrCaseReverse($pValue = '')
  606. {
  607. if (self::getIsMbstringEnabled()) {
  608. $characters = self::mb_str_split($pValue);
  609. foreach ($characters as &$character) {
  610. if (self::mb_is_upper($character)) {
  611. $character = mb_strtolower($character, 'UTF-8');
  612. } else {
  613. $character = mb_strtoupper($character, 'UTF-8');
  614. }
  615. }
  616. return implode('', $characters);
  617. }
  618. return strtolower($pValue) ^ strtoupper($pValue) ^ $pValue;
  619. }
  620. /**
  621. * Identify whether a string contains a fractional numeric value,
  622. * and convert it to a numeric if it is
  623. *
  624. * @param string &$operand string value to test
  625. * @return boolean
  626. */
  627. public static function convertToNumberIfFraction(&$operand)
  628. {
  629. if (preg_match('/^'.self::STRING_REGEXP_FRACTION.'$/i', $operand, $match)) {
  630. $sign = ($match[1] == '-') ? '-' : '+';
  631. $fractionFormula = '='.$sign.$match[2].$sign.$match[3];
  632. $operand = PHPExcel_Calculation::getInstance()->_calculateFormulaValue($fractionFormula);
  633. return true;
  634. }
  635. return false;
  636. } // function convertToNumberIfFraction()
  637. /**
  638. * Get the decimal separator. If it has not yet been set explicitly, try to obtain number
  639. * formatting information from locale.
  640. *
  641. * @return string
  642. */
  643. public static function getDecimalSeparator()
  644. {
  645. if (!isset(self::$decimalSeparator)) {
  646. $localeconv = localeconv();
  647. self::$decimalSeparator = ($localeconv['decimal_point'] != '')
  648. ? $localeconv['decimal_point'] : $localeconv['mon_decimal_point'];
  649. if (self::$decimalSeparator == '') {
  650. // Default to .
  651. self::$decimalSeparator = '.';
  652. }
  653. }
  654. return self::$decimalSeparator;
  655. }
  656. /**
  657. * Set the decimal separator. Only used by PHPExcel_Style_NumberFormat::toFormattedString()
  658. * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF
  659. *
  660. * @param string $pValue Character for decimal separator
  661. */
  662. public static function setDecimalSeparator($pValue = '.')
  663. {
  664. self::$decimalSeparator = $pValue;
  665. }
  666. /**
  667. * Get the thousands separator. If it has not yet been set explicitly, try to obtain number
  668. * formatting information from locale.
  669. *
  670. * @return string
  671. */
  672. public static function getThousandsSeparator()
  673. {
  674. if (!isset(self::$thousandsSeparator)) {
  675. $localeconv = localeconv();
  676. self::$thousandsSeparator = ($localeconv['thousands_sep'] != '')
  677. ? $localeconv['thousands_sep'] : $localeconv['mon_thousands_sep'];
  678. if (self::$thousandsSeparator == '') {
  679. // Default to .
  680. self::$thousandsSeparator = ',';
  681. }
  682. }
  683. return self::$thousandsSeparator;
  684. }
  685. /**
  686. * Set the thousands separator. Only used by PHPExcel_Style_NumberFormat::toFormattedString()
  687. * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF
  688. *
  689. * @param string $pValue Character for thousands separator
  690. */
  691. public static function setThousandsSeparator($pValue = ',')
  692. {
  693. self::$thousandsSeparator = $pValue;
  694. }
  695. /**
  696. * Get the currency code. If it has not yet been set explicitly, try to obtain the
  697. * symbol information from locale.
  698. *
  699. * @return string
  700. */
  701. public static function getCurrencyCode()
  702. {
  703. if (!isset(self::$currencyCode)) {
  704. $localeconv = localeconv();
  705. self::$currencyCode = ($localeconv['currency_symbol'] != '')
  706. ? $localeconv['currency_symbol'] : $localeconv['int_curr_symbol'];
  707. if (self::$currencyCode == '') {
  708. // Default to $
  709. self::$currencyCode = '$';
  710. }
  711. }
  712. return self::$currencyCode;
  713. }
  714. /**
  715. * Set the currency code. Only used by PHPExcel_Style_NumberFormat::toFormattedString()
  716. * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF
  717. *
  718. * @param string $pValue Character for currency code
  719. */
  720. public static function setCurrencyCode($pValue = '$')
  721. {
  722. self::$currencyCode = $pValue;
  723. }
  724. /**
  725. * Convert SYLK encoded string to UTF-8
  726. *
  727. * @param string $pValue
  728. * @return string UTF-8 encoded string
  729. */
  730. public static function SYLKtoUTF8($pValue = '')
  731. {
  732. // If there is no escape character in the string there is nothing to do
  733. if (strpos($pValue, '') === false) {
  734. return $pValue;
  735. }
  736. foreach (self::$SYLKCharacters as $k => $v) {
  737. $pValue = str_replace($k, $v, $pValue);
  738. }
  739. return $pValue;
  740. }
  741. /**
  742. * Retrieve any leading numeric part of a string, or return the full string if no leading numeric
  743. * (handles basic integer or float, but not exponent or non decimal)
  744. *
  745. * @param string $value
  746. * @return mixed string or only the leading numeric part of the string
  747. */
  748. public static function testStringAsNumeric($value)
  749. {
  750. if (is_numeric($value)) {
  751. return $value;
  752. }
  753. $v = floatval($value);
  754. return (is_numeric(substr($value, 0, strlen($v)))) ? $v : $value;
  755. }
  756. }