3 namespace Org\Mxchange\CoreFramework\Utils\String;
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Configuration\FrameworkConfiguration;
8 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
9 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
12 use \InvalidArgumentException;
15 * A string utility class
17 * @author Roland Haeder <webmaster@ship-simu.org>
19 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
20 * @license GNU GPL 3.0 or any newer version
21 * @link http://www.ship-simu.org
23 * This program is free software: you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation, either version 3 of the License, or
26 * (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36 final class StringUtils extends BaseFrameworkSystem {
40 private static $thousands = ''; // German
45 private static $decimals = ''; // German
48 * Array with bitmasks and such for pack/unpack methods to support both
49 * 32-bit and 64-bit systems
51 private static $packingData = array(
55 'right' => 0x0000ffff,
61 'left' => 0xffffffff00000000,
62 'right' => 0x00000000ffffffff,
69 * Simple 64-bit check, thanks to "Salman A" from stackoverflow.com:
71 * The integer size is 4 bytes on 32-bit and 8 bytes on a 64-bit system.
73 private static $archArrayElement = 0;
76 * Private constructor, no instance needed. If PHP would have a static initializer ...
80 private function __construct () {
81 // Call parent constructor
82 parent::__construct(__CLASS__);
85 if (empty(self::$archArrayElement)) {
87 self::$archArrayElement = (PHP_INT_SIZE === 8 ? 64 : 32);
89 // Init from configuration
90 self::$thousands = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('thousands_separator');
91 self::$decimals = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('decimals_separator');
96 * Converts dashes to underscores, e.g. useable for configuration entries
98 * @param $str The string with maybe dashes inside
99 * @return $str The converted string with no dashed, but underscores
100 * @throws NullPointerException If $str is null
101 * @throws InvalidArgumentException If $str is empty
103 public static function convertDashesToUnderscores ($str) {
107 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
108 } elseif (!is_string($str)) {
110 throw new InvalidArgumentException(sprintf('str[]=%s is not a string', gettype($str)), FrameworkConfiguration::EXCEPTION_CONFIG_KEY_IS_EMPTY);
111 } elseif ((is_string($str)) && (empty($str))) {
113 throw new InvalidArgumentException('str is empty', FrameworkConfiguration::EXCEPTION_CONFIG_KEY_IS_EMPTY);
117 $str = str_replace('-', '_', $str);
119 // Return converted string
124 * Encodes raw data (almost any type) by "serializing" it and then pack it
125 * into a "binary format".
127 * @param $rawData Raw data (almost any type)
128 * @return $encoded Encoded data
129 * @throws InvalidArgumentException If $rawData has a non-serializable data type
131 public static function encodeData ($rawData) {
132 // Make sure no objects or resources pass through
133 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: rawData[]=%s - CALLED!', gettype($rawData)));
134 if (is_object($rawData) || is_resource($rawData)) {
135 // Not all variable types should be serialized here
136 throw new InvalidArgumentException(sprintf('rawData[]=%s cannot be serialized.', gettype($rawData)));
140 $dummyInstance = new StringUtils();
142 // First "serialize" it (json_encode() is faster than serialize())
143 $encoded = self::packString(json_encode($rawData));
146 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: encoded()=%d - EXIT!', strlen($encoded)));
151 * Converts e.g. a command from URL to a valid class by keeping out bad characters
153 * @param $str The string, what ever it is needs to be converted
154 * @return $className Generated class name
156 public static final function convertToClassName (string $str) {
160 // Convert all dashes in underscores
161 $str = self::convertDashesToUnderscores($str);
163 // Now use that underscores to get classname parts for hungarian style
164 foreach (explode('_', $str) as $strPart) {
165 // Make the class name part lower case and first upper case
166 $className .= ucfirst(strtolower($strPart));
174 * Formats computer generated price values into human-understandable formats
175 * with thousand and decimal separators.
177 * @param $value The in computer format value for a price
178 * @param $currency The currency symbol (use HTML-valid characters!)
179 * @param $decNum Number of decimals after commata
180 * @return $price The for the current language formated price string
181 * @throws MissingDecimalsThousandsSeparatorException If decimals or thousands separator is missing
183 public static function formatCurrency (float $value, string $currency = '€', int $decNum = 2) {
185 $dummyInstance = new StringUtils();
187 // Reformat the US number
188 $price = number_format($value, $decNum, self::$decimals, self::$thousands) . $currency;
190 // Return as string...
195 * Pack a string into a "binary format". Please execuse me that this is
196 * widely undocumented. :-(
198 * @param $str Unpacked string
199 * @return $packed Packed string
200 * @todo Improve documentation
202 private static function packString (string $str) {
203 // First compress the string (gzcompress is okay)
204 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: str=%s - CALLED!', $str));
205 $str = gzcompress($str);
210 // And start the "encoding" loop
211 for ($idx = 0; $idx < strlen($str); $idx += self::$packingData[self::$archArrayElement]['step']) {
213 for ($i = 0; $i < self::$packingData[self::$archArrayElement]['step']; $i++) {
214 $factor = (self::$packingData[self::$archArrayElement]['step'] - 1 - $i);
216 if (($idx + $i) <= strlen($str)) {
217 $ord = ord(substr($str, ($idx + $i), 1));
219 $add = $ord * pow(256, $factor);
223 //print 'idx=' . $idx . ',i=' . $i . ',ord=' . $ord . ',factor=' . $factor . ',add=' . $add . ',big=' . $big . PHP_EOL;
227 // Left/right parts (low/high?)
228 $l = ($big & self::$packingData[self::$archArrayElement]['left']) >>self::$packingData[self::$archArrayElement]['factor'];
229 $r = $big & self::$packingData[self::$archArrayElement]['right'];
232 $chunk = str_pad(pack(self::$packingData[self::$archArrayElement]['format'], $l, $r), 8, '0', STR_PAD_LEFT);
233 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: big=%d,chunk(%d)=%s', $big, strlen($chunk), md5($chunk)));
239 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: packed=%s - EXIT!', $packed));