Removed AString and IString and turned WString into a utility class like XString for multibyte strings.
This commit is contained in:
parent
e31781c69f
commit
18397477d6
14 changed files with 285 additions and 1377 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.2311.201900
|
||||
0.2401.40206
|
||||
|
|
108
composer.lock
generated
108
composer.lock
generated
|
@ -68,16 +68,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.17.1",
|
||||
"version": "v4.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -118,9 +118,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
|
||||
},
|
||||
"time": "2023-08-13T19:53:39+00:00"
|
||||
"time": "2023-12-10T21:03:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
|
@ -235,16 +235,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.41",
|
||||
"version": "1.10.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "c6174523c2a69231df55bdc65b61655e72876d76"
|
||||
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6174523c2a69231df55bdc65b61655e72876d76",
|
||||
"reference": "c6174523c2a69231df55bdc65b61655e72876d76",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4",
|
||||
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -293,27 +293,27 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-05T12:57:57+00:00"
|
||||
"time": "2023-12-13T10:59:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.7",
|
||||
"version": "10.1.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e"
|
||||
"reference": "78c3b7625965c2513ee96569a4dbb62601784145"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/78c3b7625965c2513ee96569a4dbb62601784145",
|
||||
"reference": "78c3b7625965c2513ee96569a4dbb62601784145",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=8.1",
|
||||
"phpunit/php-file-iterator": "^4.0",
|
||||
"phpunit/php-text-template": "^3.0",
|
||||
|
@ -363,7 +363,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -371,7 +371,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-10-04T15:34:17+00:00"
|
||||
"time": "2023-12-21T15:38:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -618,16 +618,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.4.2",
|
||||
"version": "10.5.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1"
|
||||
"reference": "ed21115d505b4b4f7dc7b5651464e19a2c7f7856"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cacd8b9dd224efa8eb28beb69004126c7ca1a1a1",
|
||||
"reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ed21115d505b4b4f7dc7b5651464e19a2c7f7856",
|
||||
"reference": "ed21115d505b4b4f7dc7b5651464e19a2c7f7856",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -667,7 +667,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "10.4-dev"
|
||||
"dev-main": "10.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -699,7 +699,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.2"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -715,7 +715,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-10-26T07:21:45+00:00"
|
||||
"time": "2023-12-27T15:13:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -963,20 +963,20 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
"version": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957"
|
||||
"reference": "68ff824baeae169ec9f2137158ee529584553799"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957",
|
||||
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
|
||||
"reference": "68ff824baeae169ec9f2137158ee529584553799",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.10",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -985,7 +985,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.1-dev"
|
||||
"dev-main": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1009,7 +1009,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0"
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1017,20 +1017,20 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-28T11:50:59+00:00"
|
||||
"time": "2023-12-21T08:37:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "5.0.3",
|
||||
"version": "5.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b"
|
||||
"reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b",
|
||||
"reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/fbf413a49e54f6b9b17e12d900ac7f6101591b7f",
|
||||
"reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1043,7 +1043,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "5.0-dev"
|
||||
"dev-main": "5.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1076,7 +1076,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"security": "https://github.com/sebastianbergmann/diff/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/5.0.3"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/5.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1084,7 +1084,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-01T07:48:21+00:00"
|
||||
"time": "2023-12-22T10:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
|
@ -1292,20 +1292,20 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||
"reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d"
|
||||
"reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d",
|
||||
"reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
|
||||
"reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.10",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1338,7 +1338,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||
"security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1346,7 +1346,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-31T09:25:50+00:00"
|
||||
"time": "2023-12-21T08:38:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
|
@ -1634,16 +1634,16 @@
|
|||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1672,7 +1672,7 @@
|
|||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1680,7 +1680,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-28T10:34:58+00:00"
|
||||
"time": "2023-11-20T00:12:19+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -1693,5 +1693,5 @@
|
|||
"ext-mbstring": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
278
src/AString.php
278
src/AString.php
|
@ -1,278 +0,0 @@
|
|||
<?php
|
||||
// AString.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2023-11-09
|
||||
|
||||
namespace Index;
|
||||
|
||||
use Traversable;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Provides an immutable ASCII string with arrow methods.
|
||||
*
|
||||
* @deprecated IString, AString and WString are deprecated and will be removed. Use XString methods instead.
|
||||
*/
|
||||
final class AString implements IString {
|
||||
use XStringTrait;
|
||||
|
||||
private string $value;
|
||||
|
||||
/**
|
||||
* Create an AString instance.
|
||||
*
|
||||
* @param string $value PHP string to inherit.
|
||||
* @return AString New instance of AString.
|
||||
*/
|
||||
public function __construct(string $value) {
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getLength(): int {
|
||||
return strlen($this->value);
|
||||
}
|
||||
|
||||
public function isEmpty(): bool {
|
||||
return $this->value === '';
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an offset exists in the string.
|
||||
*
|
||||
* You should call isset($string[$offset]) instead of $string->offsetExists($offset).
|
||||
*
|
||||
* @see https://www.php.net/manual/en/arrayaccess.offsetexists.php
|
||||
* @param int $offset Character offset.
|
||||
* @return bool true if it exists, false if not.
|
||||
*/
|
||||
public function offsetExists(mixed $offset): bool {
|
||||
return isset($this->value[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an offset from the string.
|
||||
*
|
||||
* You should do $string[$offset] instead of $string->offsetGet($offset).
|
||||
*
|
||||
* @see https://www.php.net/manual/en/arrayaccess.offsetget.php
|
||||
* @param int $offset Character offset.
|
||||
* @return string Character at that offset.
|
||||
*/
|
||||
public function offsetGet(mixed $offset): mixed {
|
||||
return $this->value[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an iterator object for this string.
|
||||
*
|
||||
* @return StringIterator An iterator for this string.
|
||||
*/
|
||||
public function getIterator(): Traversable {
|
||||
return new StringIterator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data which should be serialized as json.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/jsonserializable.jsonserialize.php
|
||||
* @return mixed Data to be passed to json_encode.
|
||||
*/
|
||||
public function jsonSerialize(): mixed {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function bencodeSerialise(): mixed {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a serialized representation of this object.
|
||||
*
|
||||
* @return array Serialized data.
|
||||
*/
|
||||
public function __serialize(): array {
|
||||
return [$this->value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs an object from a serialized string.
|
||||
*
|
||||
* @param array $serialized Serialized data.
|
||||
*/
|
||||
public function __unserialize(array $serialized): void {
|
||||
$this->value = $serialized[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this string is identical to another.
|
||||
*
|
||||
* @param mixed $other An instance of AString or a PHP string.
|
||||
* @return bool true if the strings have the same value, false if not.
|
||||
*/
|
||||
public function equals(mixed $other): bool {
|
||||
return $this->compare($other) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares whether this string is identical to another.
|
||||
*
|
||||
* @param mixed $other An instance of IString or a PHP string.
|
||||
*/
|
||||
public function compare(mixed $other): int {
|
||||
return strcmp($this->value, (string)$other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new identical AString instance.
|
||||
*
|
||||
* This method is somewhat pointless, given the immutable nature of this object,
|
||||
* but rather people calling this instead of calling ->substring(0);
|
||||
*
|
||||
* @return AString A new identical instance of AString.
|
||||
*/
|
||||
public function clone(): mixed {
|
||||
return new AString($this->value);
|
||||
}
|
||||
|
||||
public function indexOf(IString|string $text, int $offset = 0): int {
|
||||
$pos = strpos($this->value, (string)$text, $offset);
|
||||
if($pos === false)
|
||||
return -1;
|
||||
return $pos;
|
||||
}
|
||||
|
||||
public function contains(IString|string $text): bool {
|
||||
return str_contains($this->value, (string)$text);
|
||||
}
|
||||
|
||||
public function substring(int $offset, int|null $length = null): IString {
|
||||
return new AString(substr($this->value, $offset, $length));
|
||||
}
|
||||
|
||||
public function replace(IString|string $search, IString|string $replace): IString {
|
||||
return new AString(str_replace((string)$search, (string)$replace, $this->value));
|
||||
}
|
||||
|
||||
public function append(IString|string $string): IString {
|
||||
return new AString($this->value . (string)$string);
|
||||
}
|
||||
|
||||
public function prepend(IString|string $string): IString {
|
||||
return new AString(((string)$string) . $this->value);
|
||||
}
|
||||
|
||||
public function split(IString|string $separator, int $limit = PHP_INT_MAX): array {
|
||||
$separator = (string)$separator;
|
||||
if(empty($separator))
|
||||
throw new InvalidArgumentException('$separator may not be empty.');
|
||||
return XArray::select(
|
||||
explode($separator, $this->value, $limit),
|
||||
fn($str) => new AString($str)
|
||||
);
|
||||
}
|
||||
|
||||
public function chunk(int $chunkSize): array {
|
||||
return XArray::select(
|
||||
str_split($this->value, $chunkSize),
|
||||
fn($str) => new AString($str)
|
||||
);
|
||||
}
|
||||
|
||||
public function trim(IString|string $characters = IString::TRIM_CHARS): IString {
|
||||
return new AString(trim($this->value, (string)$characters));
|
||||
}
|
||||
|
||||
public function trimStart(IString|string $characters = IString::TRIM_CHARS): IString {
|
||||
return new AString(ltrim($this->value, (string)$characters));
|
||||
}
|
||||
|
||||
public function trimEnd(IString|string $characters = IString::TRIM_CHARS): IString {
|
||||
return new AString(rtrim($this->value, (string)$characters));
|
||||
}
|
||||
|
||||
public function toLower(): IString {
|
||||
return new AString(strtolower($this->value));
|
||||
}
|
||||
|
||||
public function toUpper(): IString {
|
||||
return new AString(strtoupper($this->value));
|
||||
}
|
||||
|
||||
public function reverse(): IString {
|
||||
return new AString(strrev($this->value));
|
||||
}
|
||||
|
||||
public function countUnique(): int {
|
||||
return XString::countUnique($this->value);
|
||||
}
|
||||
|
||||
public function startsWith(IString|string $text): bool {
|
||||
return str_starts_with($this->value, (string)$text);
|
||||
}
|
||||
|
||||
public function endsWith(IString|string $text): bool {
|
||||
return str_ends_with($this->value, (string)$text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this AString to a WString.
|
||||
*
|
||||
* @param ?string $encoding Intended encoding, null for the Index-level default.
|
||||
* @param bool $convert true to convert the string to the target encoding, false to leave the bytes as-is.
|
||||
* @return WString A WString of the provided encoding with the value of this AString.
|
||||
*/
|
||||
public function toWString(?string $encoding = null, bool $convert = true): WString {
|
||||
$value = $this->value;
|
||||
$encoding ??= WString::getDefaultEncoding();
|
||||
if($convert)
|
||||
$value = mb_convert_encoding($value, $encoding, 'ascii');
|
||||
return new WString($value, $encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins an iterable object together with a separator to create a string.
|
||||
*
|
||||
* @param iterable $source Source object.
|
||||
* @param IString|string $separator Separator to use as glue.
|
||||
* @return AString Resulting string.
|
||||
*/
|
||||
public static function join(iterable $source, IString|string $separator = ''): AString {
|
||||
if(!is_array($source)) {
|
||||
$parts = [];
|
||||
foreach($source as $value)
|
||||
$parts[] = $value;
|
||||
$source = $parts;
|
||||
}
|
||||
|
||||
return new AString(implode((string)$separator, $source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reusable empty string instance.
|
||||
*
|
||||
* @return AString An empty string.
|
||||
*/
|
||||
public static function empty(): AString {
|
||||
static $empty = null;
|
||||
$empty ??= new AString('');
|
||||
return $empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value to AString.
|
||||
*
|
||||
* @param mixed $value Source value.
|
||||
* @return AString An AString representing the given value.
|
||||
*/
|
||||
public static function cast(mixed $value): AString {
|
||||
if($value instanceof AString)
|
||||
return $value;
|
||||
if($value instanceof WString)
|
||||
return $value->toAString();
|
||||
return new AString((string)$value);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// DateTime.php
|
||||
// Created: 2021-06-11
|
||||
// Updated: 2023-01-01
|
||||
// Updated: 2024-01-04
|
||||
|
||||
namespace Index;
|
||||
|
||||
|
@ -344,15 +344,6 @@ class DateTime extends DateTimeImmutable implements JsonSerializable, Stringable
|
|||
return $this->add(TimeSpan::fromMicroseconds($micros));
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for subtract, must exist because of the DateTimeImmutable inheritance but I don't like short names.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function sub(DateInterval $interval): DateTime {
|
||||
return $this->subtract($interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a time period from this DateTime.
|
||||
*
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
// ICloneable.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2021-05-12
|
||||
|
||||
namespace Index;
|
||||
|
||||
/**
|
||||
* Provides an interface for creating a clone of an object in a controlled manner.
|
||||
*/
|
||||
interface ICloneable {
|
||||
/**
|
||||
* Create a new object that is a copy of the current instance.
|
||||
*
|
||||
* @return mixed A copy of the current instance.
|
||||
*/
|
||||
function clone(): mixed;
|
||||
}
|
198
src/IString.php
198
src/IString.php
|
@ -1,198 +0,0 @@
|
|||
<?php
|
||||
// IString.php
|
||||
// Created: 2021-06-20
|
||||
// Updated: 2023-11-09
|
||||
|
||||
namespace Index;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use JsonSerializable;
|
||||
use Stringable;
|
||||
use Index\Serialisation\IBencodeSerialisable;
|
||||
|
||||
/**
|
||||
* @deprecated IString, AString and WString are deprecated and will be removed. Use XString methods instead.
|
||||
*/
|
||||
interface IString extends ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Stringable, IComparable, ICloneable, IEquatable, IBencodeSerialisable {
|
||||
/**
|
||||
* Default trim characters.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TRIM_CHARS = " \n\r\t\v\0";
|
||||
|
||||
/**
|
||||
* Gets the length of the string.
|
||||
*
|
||||
* @return int Length of the string.
|
||||
*/
|
||||
function getLength(): int;
|
||||
|
||||
/**
|
||||
* Returns whether the string is empty.
|
||||
*
|
||||
* @return bool true if the string is empty, false if not.
|
||||
*/
|
||||
function isEmpty(): bool;
|
||||
|
||||
/**
|
||||
* Returns the index of a substring.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.strpos
|
||||
* @param IString|string $text Substring to look for.
|
||||
* @param int $offset Offset from which to start looking.
|
||||
* @return int Offset at which the substring can be found, -1 if the substring can't be found.
|
||||
*/
|
||||
function indexOf(IString|string $text, int $offset = 0): int;
|
||||
|
||||
/**
|
||||
* Checks whether the string contains a substring.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-contains
|
||||
* @param IString|string $text Substring to look for.
|
||||
* @return bool true if it could be found, false if not.
|
||||
*/
|
||||
function contains(IString|string $text): bool;
|
||||
|
||||
/**
|
||||
* Returns a ranged substring.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.substr
|
||||
* @param int $offset Offset from which to start.
|
||||
* @param int|null $length Amount of character to copy, null for the remainder of the string.
|
||||
* @return IString An instance of IString containing the substring.
|
||||
*/
|
||||
function substring(int $offset, int|null $length = null): IString;
|
||||
|
||||
/**
|
||||
* Checks if a string starts with a given substring.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-starts-with
|
||||
* @param IString|string $text The substring to check for.
|
||||
* @return bool true if the substring was found, false if not.
|
||||
*/
|
||||
function startsWith(IString|string $text): bool;
|
||||
|
||||
/**
|
||||
* Checks if a string ends with a given substring.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-ends-with
|
||||
* @param IString|string $text The substring to check for.
|
||||
* @return bool true if the substring was found, false if not.
|
||||
*/
|
||||
function endsWith(IString|string $text): bool;
|
||||
|
||||
/**
|
||||
* Replace a substring with another substring.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-replace
|
||||
* @param IString|string $search Substring that should be replaced.
|
||||
* @param IString|string $replace Replacement values for what was found with search.
|
||||
* @return IString A new IString instance with the replaced values.
|
||||
*/
|
||||
function replace(IString|string $search, IString|string $replace): IString;
|
||||
|
||||
/**
|
||||
* Concatenates two strings with this one in the first position.
|
||||
*
|
||||
* @param IString|string $string String that should be appended.
|
||||
* @return IString A new IString instance with the combined value.
|
||||
*/
|
||||
function append(IString|string $string): IString;
|
||||
|
||||
/**
|
||||
* Concatenates two strings with this one in the last position.
|
||||
*
|
||||
* @param IString|string $string String that should be prepended.
|
||||
* @return IString A new IString instance with the combined value.
|
||||
*/
|
||||
function prepend(IString|string $string): IString;
|
||||
|
||||
/**
|
||||
* Split a string by a separator string into an array.
|
||||
*
|
||||
* Calling split with an empty string will not work, use ->chunk(1) instead.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.explode
|
||||
* @param IString|string $separator The boundary string.
|
||||
* @param int $limit Maximum number of elements expected in the array.
|
||||
* @return array The resulting array of substrings.
|
||||
*/
|
||||
function split(IString|string $separator, int $limit = PHP_INT_MAX): array;
|
||||
|
||||
/**
|
||||
* Splits a string in substring chunks of a given length.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.str-split.php
|
||||
* @param int $chunkSize Maximum length of a chunk.
|
||||
* @return array The resulting array of substrings.
|
||||
*/
|
||||
function chunk(int $chunkSize): array;
|
||||
|
||||
/**
|
||||
* Strip whitespace or other characters from the beginning and end of a string.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.trim
|
||||
* @param IString|string $characters Characters to strip.
|
||||
* @return IString A new instance of IString with the characters removed.
|
||||
*/
|
||||
function trim(IString|string $characters = self::TRIM_CHARS): IString;
|
||||
|
||||
/**
|
||||
* Strip whitespace or other characters from the beginning of a string.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.ltrim.php
|
||||
* @param IString|string $characters Characters to strip.
|
||||
* @return IString A new instance of IString with the characters removed.
|
||||
*/
|
||||
function trimStart(IString|string $characters = self::TRIM_CHARS): IString;
|
||||
|
||||
/**
|
||||
* Strip whitespace or other characters from the end of a string.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.rtrim.php
|
||||
* @param IString|string $characters Characters to strip.
|
||||
* @return IString A new instance of IString with the characters removed.
|
||||
*/
|
||||
function trimEnd(IString|string $characters = self::TRIM_CHARS): IString;
|
||||
|
||||
/**
|
||||
* Convert string to lowercase.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.strtolower.php
|
||||
* @return IString A new IString instance with all lowercase characters.
|
||||
*/
|
||||
function toLower(): IString;
|
||||
|
||||
/**
|
||||
* Convert string to uppercase.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.strtoupper.php
|
||||
* @return IString A new IString instance with all uppercase characters.
|
||||
*/
|
||||
function toUpper(): IString;
|
||||
|
||||
/**
|
||||
* Reverses a string.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.strrev
|
||||
* @return IString A new IString instance containing the reversed string.
|
||||
*/
|
||||
function reverse(): IString;
|
||||
|
||||
/**
|
||||
* Counts unique characters in a string.
|
||||
*
|
||||
* @return int Unique character count.
|
||||
*/
|
||||
function countUnique(): int;
|
||||
|
||||
/**
|
||||
* Returns a copy of the standard PHP string.
|
||||
*
|
||||
* @return string PHP string.
|
||||
*/
|
||||
function __toString(): string;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
// StringIterator.php
|
||||
// Created: 2022-02-02
|
||||
// Updated: 2023-11-09
|
||||
|
||||
namespace Index;
|
||||
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Provides an iterator for IString types.
|
||||
*
|
||||
* @deprecated Will be removed along with IString, AString and WString.
|
||||
*/
|
||||
class StringIterator implements Iterator {
|
||||
private IString $value;
|
||||
private int $length;
|
||||
private int $index = 0;
|
||||
private bool $wasValid = false;
|
||||
|
||||
/**
|
||||
* Creates the iterator.
|
||||
*
|
||||
* @param IString $string String to iterate.
|
||||
*/
|
||||
public function __construct(IString $string) {
|
||||
$this->value = $string;
|
||||
$this->length = $string->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current character.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/iterator.current.php
|
||||
* @return mixed Current character.
|
||||
*/
|
||||
public function current(): mixed {
|
||||
return $this->value[$this->index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the current character.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/iterator.key.php
|
||||
* @return int Index of the current character.
|
||||
*/
|
||||
public function key(): mixed {
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move forward to the next character.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/iterator.next.php
|
||||
*/
|
||||
public function next(): void {
|
||||
$next = $this->index + 1;
|
||||
$this->wasValid = $next < $this->length;
|
||||
|
||||
if($this->wasValid)
|
||||
$this->index = $next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind to the first character.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/iterator.rewind.php
|
||||
*/
|
||||
public function rewind(): void {
|
||||
$this->index = 0;
|
||||
$this->wasValid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current index is valid.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/iterator.rewind.php
|
||||
* @return bool Whether the current index is valid.
|
||||
*/
|
||||
public function valid(): bool {
|
||||
return $this->wasValid;
|
||||
}
|
||||
}
|
463
src/WString.php
463
src/WString.php
|
@ -1,394 +1,175 @@
|
|||
<?php
|
||||
// WString.php
|
||||
// Created: 2021-06-22
|
||||
// Updated: 2023-11-09
|
||||
// Updated: 2024-01-04
|
||||
|
||||
namespace Index;
|
||||
|
||||
use Traversable;
|
||||
use InvalidArgumentException;
|
||||
use ValueError;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* Provides an immutable multi-byte string with arrow methods.
|
||||
*
|
||||
* @deprecated IString, AString and WString are deprecated and will be removed. Use XString methods instead.
|
||||
* Provides various helper methods for multibyte strings.
|
||||
*/
|
||||
final class WString implements IString {
|
||||
use XStringTrait;
|
||||
final class WString {
|
||||
/**
|
||||
* Default characters for ::trim, ::trimStart and ::trimEnd.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const TRIM_CHARS = "\0\t\n\v\f\r \u{85}\u{a0}\u{1680}\u{180e}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200a}\u{200b}\u{200c}\u{200d}\u{2028}\u{2029}\u{202f}\u{205f}\u{2060}\u{3000}\u{feff}";
|
||||
private const TRIM_CHARS_CHARSET = 'UTF-8';
|
||||
|
||||
public const DEFAULT_ENCODING = 'utf-8';
|
||||
private const TRIM_START = 0x01;
|
||||
private const TRIM_END = 0x02;
|
||||
private const TRIM_ALL = self::TRIM_START | self::TRIM_END;
|
||||
|
||||
private static $defaultEncoding = self::DEFAULT_ENCODING;
|
||||
|
||||
private string $value;
|
||||
private string $encoding;
|
||||
|
||||
public function __construct(string $value = '', ?string $encoding = null) {
|
||||
$encoding ??= self::$defaultEncoding;
|
||||
|
||||
if(!mb_check_encoding($value, $encoding))
|
||||
throw new InvalidArgumentException('$value is not a valid value for the selected encoding.');
|
||||
|
||||
$this->value = $value;
|
||||
$this->encoding = mb_preferred_mime_name($encoding);
|
||||
}
|
||||
|
||||
public function getLength(): int {
|
||||
return mb_strlen($this->value, $this->encoding);
|
||||
/**
|
||||
* Checks if a multibyte string starts with a given substring.
|
||||
*
|
||||
* @param Stringable|string $haystack String to search in.
|
||||
* @param Stringable|string $needle Sustring to search for in the haystack.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return bool true if haystack begins with needle, false otherwise.
|
||||
*/
|
||||
public static function startsWith(Stringable|string $haystack, Stringable|string $needle, ?string $encoding = null): bool {
|
||||
return mb_strpos((string)$haystack, (string)$needle, encoding: $encoding) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of bytes the string contains.
|
||||
* Checks if a multibyte string ends with a given substring.
|
||||
*
|
||||
* @return int Amount of raw bytes.
|
||||
* @param Stringable|string $haystack String to search in.
|
||||
* @param Stringable|string $needle Sustring to search for in the haystack.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return bool true if haystack ends with needle, false otherwise.
|
||||
*/
|
||||
public function getByteCount(): int {
|
||||
return strlen($this->value);
|
||||
public static function endsWith(Stringable|string $haystack, Stringable|string $needle, ?string $encoding = null): bool {
|
||||
$haystack = (string)$haystack;
|
||||
$haystackLength = mb_strlen($haystack, $encoding);
|
||||
|
||||
$needle = (string)$needle;
|
||||
$needleLength = mb_strlen($needle, $encoding);
|
||||
|
||||
return mb_substr($haystack, -$needleLength, encoding: $encoding) === $needle;
|
||||
}
|
||||
|
||||
public function isEmpty(): bool {
|
||||
// an empty string is an empty string so this should be fine regardless of encoding
|
||||
return $this->value === '';
|
||||
}
|
||||
private static function trimInternal(Stringable|string $string, string $chars, ?string $encoding, ?string $charsEncoding, int $flags): string {
|
||||
$encoding = $encoding === null ? mb_internal_encoding() : mb_preferred_mime_name($encoding);
|
||||
$charsEncoding = $charsEncoding === null ? self::TRIM_CHARS_CHARSET : mb_preferred_mime_name($charsEncoding);
|
||||
|
||||
public function indexOf(IString|string $text, int $offset = 0): int {
|
||||
$text = (string)self::castEncoding($text, $this->encoding);
|
||||
$pos = mb_strpos($this->value, $text, $offset, $this->encoding);
|
||||
if($pos === false)
|
||||
return -1;
|
||||
return $pos;
|
||||
}
|
||||
// this fucks, i hate character sets
|
||||
if($encoding !== $charsEncoding) {
|
||||
$questionMarkCharsEnc = mb_convert_encoding('?', $charsEncoding, 'utf-8');
|
||||
$questionMarkStrEnc = mb_convert_encoding('?', $encoding, 'utf-8');
|
||||
$hasQuestionMark = mb_strpos($chars, $questionMarkCharsEnc, encoding: $charsEncoding) !== false;
|
||||
$chars = mb_convert_encoding($chars, $encoding, $charsEncoding);
|
||||
|
||||
public function contains(IString|string $text): bool {
|
||||
return str_contains($this->value, (string)$text);
|
||||
}
|
||||
if(!$hasQuestionMark) {
|
||||
$charsSplit = mb_str_split($chars, encoding: $encoding);
|
||||
$chars = [];
|
||||
foreach($charsSplit as $char) {
|
||||
if(in_array($char, $chars))
|
||||
continue;
|
||||
$chars[] = $char;
|
||||
}
|
||||
|
||||
public function substring(int $offset, int|null $length = null): IString {
|
||||
return new WString(mb_substr($this->value, $offset, $length, $this->encoding), $this->encoding);
|
||||
}
|
||||
$chars = implode($chars);
|
||||
}
|
||||
}
|
||||
|
||||
public function startsWith(IString|string $text): bool {
|
||||
$text = self::castEncoding($text, $this->encoding);
|
||||
return $this->substring(0, $text->getLength())->equals($text);
|
||||
}
|
||||
|
||||
public function endsWith(IString|string $text): bool {
|
||||
$text = self::castEncoding($text, $this->encoding);
|
||||
return $this->substring(0 - $text->getLength())->equals($text);
|
||||
}
|
||||
|
||||
public function replace(IString|string $search, IString|string $replace): IString {
|
||||
$search = (string)self::castEncoding($search, $this->encoding);
|
||||
$replace = (string)self::castEncoding($replace, $this->encoding);
|
||||
$parts = self::doRegex(fn() => mb_split(preg_quote($search), $this->value));
|
||||
$subject = implode($replace, $parts);
|
||||
return new WString($subject, $this->encoding);
|
||||
}
|
||||
|
||||
public function append(IString|string $string): IString {
|
||||
$string = self::castEncoding($string, $this->encoding);
|
||||
return new WString($this->value . $string->value, $this->encoding);
|
||||
}
|
||||
|
||||
public function prepend(IString|string $string): IString {
|
||||
$string = self::castEncoding($string, $this->encoding);
|
||||
return new WString($string->value . $this->value, $this->encoding);
|
||||
}
|
||||
|
||||
public function split(IString|string $separator, int $limit = PHP_INT_MAX): array {
|
||||
return XArray::select(
|
||||
self::doRegex(fn() => mb_split(preg_quote((string)$separator), $this->value, $limit)),
|
||||
fn($str) => new WString($str, $this->encoding)
|
||||
);
|
||||
}
|
||||
|
||||
public function chunk(int $chunkSize): array {
|
||||
return XArray::select(
|
||||
mb_str_split($this->value, $chunkSize, $this->encoding),
|
||||
fn($str) => new WString($str, $this->encoding)
|
||||
);
|
||||
}
|
||||
|
||||
private function trimInternal(IString|string $characters, int $flags): IString {
|
||||
if($flags & 0x01) {
|
||||
if($characters instanceof WString)
|
||||
$characters = (string)$characters->convertEncoding($this->encoding);
|
||||
else
|
||||
$characters = mb_convert_encoding((string)$characters, $this->encoding, 'ascii');
|
||||
} else
|
||||
$characters = (string)$characters;
|
||||
$string = (string)$string;
|
||||
$split = mb_str_split($string, encoding: $encoding);
|
||||
$length = mb_strlen($string, $encoding);
|
||||
|
||||
$start = 0;
|
||||
$end = $this->getLength() - 1;
|
||||
$end = $length - 1;
|
||||
|
||||
if($flags & 0x02)
|
||||
for(; $start < $this->getLength(); ++$start)
|
||||
if(mb_strpos($characters, $this[$start], 0, $this->encoding) === false)
|
||||
if($flags & self::TRIM_START)
|
||||
for(; $start < $length; ++$start)
|
||||
if(mb_strpos($chars, $split[$start], encoding: $encoding) === false)
|
||||
break;
|
||||
|
||||
if($flags & 0x04)
|
||||
if($flags & self::TRIM_END)
|
||||
for(; $end > 0; --$end)
|
||||
if(mb_strpos($characters, $this[$end], 0, $this->encoding) === false)
|
||||
if(mb_strpos($chars, $split[$end], encoding: $encoding) === false)
|
||||
break;
|
||||
|
||||
return $this->substring($start, $end - $start + 1);
|
||||
return mb_substr($string, $start, $end - $start + 1, $encoding);
|
||||
}
|
||||
|
||||
public function trim(IString|string $characters = IString::TRIM_CHARS, bool $convertChars = true): IString {
|
||||
$flags = 0x06;
|
||||
if($convertChars) $flags |= 0x01;
|
||||
return $this->trimInternal($characters, $flags);
|
||||
/**
|
||||
* Strip whitespace (or other characters) from the start and end of a multibyte string.
|
||||
*
|
||||
* @param Stringable|string $string Input string.
|
||||
* @param string $chars Characters to strip. List all characters you want. .. operator from trim is not supported.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return string Trimmed string.
|
||||
*/
|
||||
public static function trim(Stringable|string $string, string $chars = self::TRIM_CHARS, ?string $encoding = null, ?string $charsEncoding = null): string {
|
||||
return self::trimInternal($string, $chars, $encoding, $charsEncoding, self::TRIM_ALL);
|
||||
}
|
||||
|
||||
public function trimStart(IString|string $characters = IString::TRIM_CHARS, bool $convertChars = true): IString {
|
||||
$flags = 0x02;
|
||||
if($convertChars) $flags |= 0x01;
|
||||
return $this->trimInternal($characters, $flags);
|
||||
/**
|
||||
* Strip whitespace (or other characters) from the start of a multibyte string.
|
||||
*
|
||||
* @param Stringable|string $string Input string.
|
||||
* @param string $chars Characters to strip. List all characters you want. .. operator from ltrim is not supported.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return string Trimmed string.
|
||||
*/
|
||||
public static function trimStart(Stringable|string $string, string $chars = self::TRIM_CHARS, ?string $encoding = null, ?string $charsEncoding = null): string {
|
||||
return self::trimInternal($string, $chars, $encoding, $charsEncoding, self::TRIM_START);
|
||||
}
|
||||
|
||||
public function trimEnd(IString|string $characters = IString::TRIM_CHARS, bool $convertChars = true): IString {
|
||||
$flags = 0x04;
|
||||
if($convertChars) $flags |= 0x01;
|
||||
return $this->trimInternal($characters, $flags);
|
||||
/**
|
||||
* Strip whitespace (or other characters) from the end of a multibyte string.
|
||||
*
|
||||
* @param Stringable|string $string Input string.
|
||||
* @param string $chars Characters to strip. List all characters you want. .. operator from rtrim is not supported.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return string Trimmed string.
|
||||
*/
|
||||
public static function trimEnd(Stringable|string $string, string $chars = self::TRIM_CHARS, ?string $encoding = null, ?string $charsEncoding = null): string {
|
||||
return self::trimInternal($string, $chars, $encoding, $charsEncoding, self::TRIM_END);
|
||||
}
|
||||
|
||||
public function toLower(): IString {
|
||||
return new WString(mb_strtolower($this->value, $this->encoding), $this->encoding);
|
||||
/**
|
||||
* Reverses a multibyte string.
|
||||
*
|
||||
* @param Stringable|string $string String to reverse.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return string Reversed string.
|
||||
*/
|
||||
public static function reverse(Stringable|string $string, ?string $encoding = null): string {
|
||||
return implode(array_reverse(mb_str_split((string)$string, encoding: $encoding)));
|
||||
}
|
||||
|
||||
public function toUpper(): IString {
|
||||
return new WString(mb_strtoupper($this->value, $this->encoding), $this->encoding);
|
||||
}
|
||||
|
||||
public function reverse(): IString {
|
||||
$chars = [];
|
||||
foreach($this as $char)
|
||||
$chars[] = $char;
|
||||
return new WString(implode(array_reverse($chars)), $this->encoding);
|
||||
}
|
||||
|
||||
public function countUnique(): int {
|
||||
/**
|
||||
* Counts unique characters in a string.
|
||||
*
|
||||
* @param Stringable|string $string String to count unique characters of.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return int Unique character count.
|
||||
*/
|
||||
public static function countUnique(Stringable|string $string, ?string $encoding = null): int {
|
||||
$string = mb_str_split((string)$string, encoding: $encoding);
|
||||
$chars = [];
|
||||
|
||||
foreach($this as $char)
|
||||
foreach($string as $char)
|
||||
if(!in_array($char, $chars, true))
|
||||
$chars[] = $char;
|
||||
|
||||
return count($chars);
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function toAString(bool $convert = true): AString {
|
||||
$value = $this->value;
|
||||
if($convert && self::sameEncoding('ascii', $this->encoding))
|
||||
$value = mb_convert_encoding($value, 'ascii', $this->encoding);
|
||||
return new AString($value);
|
||||
}
|
||||
|
||||
public function getEncoding(): string {
|
||||
return $this->encoding;
|
||||
}
|
||||
|
||||
public function convertEncoding(string $encoding): WString {
|
||||
if(self::sameEncoding($encoding, $this->encoding))
|
||||
return $this;
|
||||
$value = mb_convert_encoding($this->value, $encoding, $this->encoding);
|
||||
return new WString($value, $encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an offset exists in the string.
|
||||
* Check if a multibyte string is null or whitespace.
|
||||
*
|
||||
* You should call isset($string[$offset]) instead of $string->offsetExists($offset).
|
||||
*
|
||||
* @see https://www.php.net/manual/en/arrayaccess.offsetexists.php
|
||||
* @param int $offset Character offset.
|
||||
* @return bool true if it exists, false if not.
|
||||
* @param Stringable|string|null $string String to check for whitespace.
|
||||
* @param ?string $encoding String character encoding. null for mb_internal_encoding value.
|
||||
* @return bool true if the string is whitespace, false if not.
|
||||
*/
|
||||
public function offsetExists(mixed $offset): bool {
|
||||
$offset = (int)$offset;
|
||||
return $offset >= 0 && $offset < $this->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an offset from the string.
|
||||
*
|
||||
* You should do $string[$offset] instead of $string->offsetGet($offset).
|
||||
*
|
||||
* @see https://www.php.net/manual/en/arrayaccess.offsetget.php
|
||||
* @param int $offset Character offset.
|
||||
* @return string Character at that offset.
|
||||
*/
|
||||
public function offsetGet(mixed $offset): mixed {
|
||||
return mb_substr($this->value, (int)$offset, 1, $this->encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an iterator object for this string.
|
||||
*
|
||||
* @return StringIterator An iterator for this string.
|
||||
*/
|
||||
public function getIterator(): Traversable {
|
||||
return new StringIterator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data which should be serialized as json.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/jsonserializable.jsonserialize.php
|
||||
* @return mixed Data to be passed to json_encode.
|
||||
*/
|
||||
public function jsonSerialize(): mixed {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function bencodeSerialise(): mixed {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a serialized representation of this object.
|
||||
*
|
||||
* @return array Serialized data.
|
||||
*/
|
||||
public function __serialize(): array {
|
||||
return [$this->encoding, $this->value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs an object from a serialized string.
|
||||
*
|
||||
* @param array $serialized Serialized data.
|
||||
*/
|
||||
public function __unserialize(array $serialized): void {
|
||||
[$this->encoding, $this->value] = $serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this string is identical to another.
|
||||
*
|
||||
* @param mixed $other An instance of IString or a PHP string.
|
||||
* @return bool true if the strings have the same value, false if not.
|
||||
*/
|
||||
public function equals(mixed $other): bool {
|
||||
return $this->compare($other) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares whether this string is identical to another.
|
||||
*
|
||||
* @param mixed $other An instance of IString or a PHP string.
|
||||
*/
|
||||
public function compare(mixed $other): int {
|
||||
$other = self::castEncoding($other, $this->encoding);
|
||||
return strcmp($this->value, (string)$other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new identical WString instance.
|
||||
*
|
||||
* This method is somewhat pointless, given the immutable nature of this object,
|
||||
* but rather people calling this instead of calling ->substring(0);
|
||||
*
|
||||
* @return WString A new identical instance of WString.
|
||||
*/
|
||||
public function clone(): mixed {
|
||||
return new WString($this->value, $this->encoding);
|
||||
}
|
||||
|
||||
private function doRegex(callable $callback): mixed {
|
||||
$encoding = self::getRegexEncoding();
|
||||
self::setRegexEncoding($this->encoding);
|
||||
$result = $callback();
|
||||
self::setRegexEncoding($encoding);
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function sameEncoding(string $name1, string $name2): bool {
|
||||
return mb_preferred_mime_name($name1) === mb_preferred_mime_name($name2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins an iterable object together with a separator to create a string.
|
||||
*
|
||||
* @param iterable $source Source object.
|
||||
* @param IString|string $separator Separator to use as glue.
|
||||
* @param ?string $encoding Desired encoding, null for Index default.
|
||||
* @return WString Resulting string.
|
||||
*/
|
||||
public static function join(iterable $source, IString|string $separator = '', ?string $encoding = null): WString {
|
||||
// func probably doesn't work entirely as intended
|
||||
$encoding ??= self::getDefaultEncoding();
|
||||
$separator = self::castEncoding($separator, $encoding);
|
||||
if(!is_array($source)) {
|
||||
$parts = [];
|
||||
foreach($source as $value)
|
||||
$parts[] = $value;
|
||||
$source = $parts;
|
||||
}
|
||||
|
||||
return new WString(implode((string)$separator, $source), $encoding);
|
||||
}
|
||||
|
||||
public static function getDefaultEncoding(): string {
|
||||
return self::$defaultEncoding;
|
||||
}
|
||||
|
||||
public static function setDefaultEncoding(string $encoding = ''): void {
|
||||
if(empty($encoding))
|
||||
self::$defaultEncoding = self::DEFAULT_ENCODING;
|
||||
else {
|
||||
try {
|
||||
if(mb_encoding_aliases($encoding) !== false)
|
||||
self::$defaultEncoding = $encoding;
|
||||
} catch(ValueError $ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getInternalEncoding(): string {
|
||||
return mb_internal_encoding();
|
||||
}
|
||||
|
||||
public static function setInternalEncoding(string $encoding): void {
|
||||
mb_internal_encoding($encoding);
|
||||
}
|
||||
|
||||
public static function getRegexEncoding(): string {
|
||||
return mb_regex_encoding();
|
||||
}
|
||||
|
||||
public static function setRegexEncoding(string $encoding): void {
|
||||
mb_regex_encoding($encoding);
|
||||
}
|
||||
|
||||
public static function fromRequest(string $raw): WString {
|
||||
return new WString($raw, self::getInternalEncoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reusable empty string instance.
|
||||
*
|
||||
* @return WString An empty string.
|
||||
*/
|
||||
public static function empty(): WString {
|
||||
static $empty = null;
|
||||
$empty ??= new WString('');
|
||||
return $empty;
|
||||
}
|
||||
|
||||
public static function cast(mixed $string): WString {
|
||||
if($string instanceof WString)
|
||||
return $string;
|
||||
if($string instanceof AString)
|
||||
return $string->toWString('ascii', false);
|
||||
return new WString((string)$string, 'ascii');
|
||||
}
|
||||
|
||||
public static function castEncoding(mixed $string, string $encoding): WString {
|
||||
return self::cast($string)->convertEncoding($encoding);
|
||||
public static function nullOrWhitespace(Stringable|string|null $string, ?string $encoding = null): bool {
|
||||
return $string === null || self::trim((string)$string, encoding: $encoding) === '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// XString.php
|
||||
// Created: 2022-02-03
|
||||
// Updated: 2023-11-09
|
||||
// Updated: 2024-01-04
|
||||
|
||||
namespace Index;
|
||||
|
||||
|
@ -19,6 +19,28 @@ final class XString {
|
|||
*/
|
||||
public const RANDOM_CHARS = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789';
|
||||
|
||||
/**
|
||||
* Generates a random string of user specified length.
|
||||
*
|
||||
* @param int $length Desired length of the string.
|
||||
* @param string $chars Set of characters to pick from. Default set contains the alphabet in upper- and lowercase and numbers 0 thru 9.
|
||||
* @return string The generated string.
|
||||
*/
|
||||
public static function random(int $length, string $chars = self::RANDOM_CHARS): string {
|
||||
if($length < 1)
|
||||
throw new InvalidArgumentException('$length must be at least 1.');
|
||||
if($chars === '')
|
||||
throw new InvalidArgumentException('$chars may not be empty.');
|
||||
|
||||
$string = '';
|
||||
$count = strlen($chars) - 1;
|
||||
|
||||
while($length-- > 0)
|
||||
$string .= $chars[random_int(0, $count)];
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts special characters to HTML entities.
|
||||
*
|
||||
|
@ -63,9 +85,7 @@ final class XString {
|
|||
* @return bool true if the string is empty, false if not.
|
||||
*/
|
||||
public static function nullOrEmpty(Stringable|string|null $string): bool {
|
||||
if($string === null)
|
||||
return true;
|
||||
return empty((string)$string);
|
||||
return $string === null || (string)$string === '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,30 +95,6 @@ final class XString {
|
|||
* @return bool true if the string is whitespace, false if not.
|
||||
*/
|
||||
public static function nullOrWhitespace(Stringable|string|null $string): bool {
|
||||
if($string === null)
|
||||
return true;
|
||||
return empty(trim((string)$string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random string of user specified length.
|
||||
*
|
||||
* @param int $length Desired length of the string.
|
||||
* @param string $chars Set of characters to pick from. Default set contains the alphabet in upper- and lowercase and numbers 0 thru 9.
|
||||
* @return string The generated string.
|
||||
*/
|
||||
public static function random(int $length, string $chars = self::RANDOM_CHARS): string {
|
||||
if($length < 1)
|
||||
throw new InvalidArgumentException('$length must be at least 1.');
|
||||
if($chars === '')
|
||||
throw new InvalidArgumentException('$chars may not be empty.');
|
||||
|
||||
$string = '';
|
||||
$count = strlen($chars) - 1;
|
||||
|
||||
while($length-- > 0)
|
||||
$string .= $chars[random_int(0, $count)];
|
||||
|
||||
return $string;
|
||||
return $string === null || trim((string)$string) === '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
// XStringTrait.php
|
||||
// Created: 2021-06-22
|
||||
// Updated: 2023-11-09
|
||||
|
||||
namespace Index;
|
||||
|
||||
use BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Provides method implementations that are common between all string types.
|
||||
* @internal
|
||||
* @deprecated Will be removed along with IString, AString and WString.
|
||||
*/
|
||||
trait XStringTrait {
|
||||
/**
|
||||
* Gets the length of the string.
|
||||
*
|
||||
* For compliance with the Countable interface.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/class.countable.php
|
||||
* @return int Length of the string.
|
||||
*/
|
||||
public function count(): int {
|
||||
return $this->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Necessary to comply with the ArrayAccess interface.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function offsetSet(mixed $offset, mixed $value): void {
|
||||
throw new BadMethodCallException('Strings are immutable.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Necessary to comply with the ArrayAccess interface.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function offsetUnset(mixed $offset): void {
|
||||
throw new BadMethodCallException('Strings are immutable.');
|
||||
}
|
||||
|
||||
public function toBool(): bool {
|
||||
return boolval((string)$this);
|
||||
}
|
||||
|
||||
public function toInt(int $base = 10): int {
|
||||
return $base === 10 ? (int)(string)$this : intval((string)$this, $base);
|
||||
}
|
||||
|
||||
public function toFloat(): float {
|
||||
return (float)(string)$this;
|
||||
}
|
||||
|
||||
public function escape(
|
||||
int $flags = ENT_COMPAT | ENT_HTML5,
|
||||
?string $encoding = null,
|
||||
bool $doubleEncoding = true
|
||||
): IString {
|
||||
return new AString(XString::escape($this, $flags, $encoding, $doubleEncoding));
|
||||
}
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
<?php
|
||||
// StringTest.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2023-07-05
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Index\XArray;
|
||||
use Index\AString;
|
||||
use Index\WString;
|
||||
use Index\XString;
|
||||
|
||||
/**
|
||||
* @covers AString
|
||||
* @covers WString
|
||||
* @covers XString
|
||||
*/
|
||||
final class StringTest extends TestCase {
|
||||
public function testLength(): void {
|
||||
$ascii = new AString('soup');
|
||||
$this->assertEquals(4, $ascii->getLength());
|
||||
$this->assertEquals(4, count($ascii));
|
||||
$this->assertFalse($ascii->isEmpty());
|
||||
|
||||
$utf8 = new WString('ßóúþ', 'utf-8');
|
||||
$this->assertEquals(4, $utf8->getLength());
|
||||
$this->assertEquals(4, count($utf8));
|
||||
$this->assertEquals(8, $utf8->getByteCount());
|
||||
$this->assertFalse($utf8->isEmpty());
|
||||
|
||||
$utf16be = new WString("\x00\xDF\x00\xF3\x00\xFA\x00\xFE", 'UTF-16BE');
|
||||
$this->assertEquals(4, $utf16be->getLength());
|
||||
$this->assertEquals(4, count($utf16be));
|
||||
$this->assertEquals(8, $utf16be->getByteCount());
|
||||
$this->assertFalse($utf16be->isEmpty());
|
||||
|
||||
$utf32le = new WString("\xDF\x00\x00\x00\xF3\x00\x00\x00\xFA\x00\x00\x00\xFE\x00\x00\x00", 'UTF-32LE');
|
||||
$this->assertEquals(4, $utf32le->getLength());
|
||||
$this->assertEquals(4, count($utf32le));
|
||||
$this->assertEquals(16, $utf32le->getByteCount());
|
||||
$this->assertFalse($utf32le->isEmpty());
|
||||
|
||||
$this->assertTrue($utf8->equals($utf16be));
|
||||
$this->assertTrue($utf16be->equals($utf32le));
|
||||
$this->assertTrue($utf32le->equals($utf8));
|
||||
}
|
||||
|
||||
public function testToString(): void {
|
||||
$ascii = new AString('Windows XP');
|
||||
$this->assertEquals('Windows XP', (string)$ascii);
|
||||
|
||||
$utf16be = new WString("\x00\xDF\x00\xF3\x00\xFA\x00\xFE", 'UTF-16BE');
|
||||
$this->assertEquals("\x00\xDF\x00\xF3\x00\xFA\x00\xFE", (string)$utf16be);
|
||||
|
||||
$utf32le = $utf16be->convertEncoding('utf-32le');
|
||||
$this->assertEquals("\xDF\x00\x00\x00\xF3\x00\x00\x00\xFA\x00\x00\x00\xFE\x00\x00\x00", (string)$utf32le);
|
||||
}
|
||||
|
||||
public function testArrayAccess(): void {
|
||||
$ascii = new AString('Akai Haato');
|
||||
|
||||
$this->assertEquals('a', $ascii[2]);
|
||||
$this->assertEquals('H', $ascii[5]);
|
||||
|
||||
$this->assertTrue(isset($ascii[6]));
|
||||
$this->assertFalse(isset($ascii[23]));
|
||||
|
||||
$this->expectException(\BadMethodCallException::class);
|
||||
$ascii[4] = '_';
|
||||
|
||||
$this->expectException(\BadMethodCallException::class);
|
||||
unset($ascii[7]);
|
||||
|
||||
$utf16le = $ascii->toWString('utf-16le');
|
||||
|
||||
$this->assertEquals('a', $utf16le[2]);
|
||||
$this->assertEquals('H', $utf16le[5]);
|
||||
|
||||
$this->assertTrue(isset($utf16le[6]));
|
||||
$this->assertFalse(isset($utf16le[23]));
|
||||
|
||||
$this->expectException(\BadMethodCallException::class);
|
||||
$utf16le[4] = '_';
|
||||
|
||||
$this->expectException(\BadMethodCallException::class);
|
||||
unset($utf16le[7]);
|
||||
}
|
||||
|
||||
public function testJsonSerialize(): void {
|
||||
$ascii = new AString('Mewow');
|
||||
$this->assertEquals('Mewow', json_decode(json_encode($ascii)));
|
||||
$this->assertEquals('Mewow', json_decode(json_encode($ascii->toWString('Shift_JIS'))));
|
||||
}
|
||||
|
||||
public function testSerializable(): void {
|
||||
$ascii = new AString('Futami Mami');
|
||||
$asciiSerialised = serialize($ascii);
|
||||
|
||||
$sjis = new WString("\x91\x6F\x8A\x43\x90\x5E\x94\xFC", 'Shift_JIS');
|
||||
$sjisSerialised = serialize($sjis);
|
||||
|
||||
$asciiUnserialised = unserialize($asciiSerialised);
|
||||
$this->assertTrue($ascii->equals($asciiUnserialised));
|
||||
$this->assertTrue($asciiUnserialised->equals('Futami Mami'));
|
||||
|
||||
$sjisUnserialised = unserialize($sjisSerialised);
|
||||
$this->assertTrue($sjis->equals($sjisUnserialised));
|
||||
$this->assertTrue($sjisUnserialised->equals(new WString('双海真美', 'utf-8')));
|
||||
}
|
||||
|
||||
public function testEquals(): void {
|
||||
$ascii = new AString('Misaka Mikoto');
|
||||
$this->assertTrue($ascii->equals($ascii));
|
||||
$this->assertTrue($ascii->equals('Misaka Mikoto'));
|
||||
$this->assertTrue($ascii->equals(new AString('Misaka Mikoto')));
|
||||
$this->assertFalse($ascii->equals('Mewow'));
|
||||
$this->assertFalse($ascii->equals(new AString('Ndx Mewow')));
|
||||
}
|
||||
|
||||
public function testConcat(): void {
|
||||
$ndxString1 = new AString('Akai ');
|
||||
$ndxString2 = $ndxString1->append('Haato');
|
||||
$ndxString3 = $ndxString1->append(new AString('Haato'));
|
||||
$ndxString4 = (new AString('Haato'))->prepend($ndxString1);
|
||||
|
||||
$this->assertEquals('Akai Haato', (string)$ndxString2);
|
||||
$this->assertEquals('Akai Haato', (string)$ndxString3);
|
||||
$this->assertEquals('Akai Haato', (string)$ndxString4);
|
||||
}
|
||||
|
||||
public function testSplit(): void {
|
||||
$ascii = new AString('Kasane Teto');
|
||||
$asciiArr = ['Kasane', 'Teto'];
|
||||
$this->assertTrue(XArray::sequenceEquals($asciiArr, $ascii->split(' ')));
|
||||
|
||||
$utf16le = new WString("\x42\x30\x02\x30\x44\x30\x02\x30\x46\x30\x02\x30\x48\x30\x02\x30\x4A\x30\x02\x30", 'utf-16le');
|
||||
$utf16leArr = [
|
||||
new WString("\x42\x30", 'utf-16le'),
|
||||
new WString("\x44\x30", 'utf-16le'),
|
||||
new WString("\x46\x30", 'utf-16le'),
|
||||
new WString("\x48\x30", 'utf-16le'),
|
||||
new WString("\x4A\x30", 'utf-16le'),
|
||||
new WString("", 'utf-16le'),
|
||||
];
|
||||
$this->assertTrue(XArray::sequenceEquals($utf16leArr, $utf16le->split(new WString("\x02\x30", 'utf-16le'))));
|
||||
|
||||
$utf8 = new WString('あ。い。う。え。お。', 'utf-8');
|
||||
$utf8Arr = [
|
||||
new Wstring('あ', 'utf-8'),
|
||||
new Wstring('い', 'utf-8'),
|
||||
new Wstring('う', 'utf-8'),
|
||||
new Wstring('え', 'utf-8'),
|
||||
new Wstring('お', 'utf-8'),
|
||||
new Wstring('', 'utf-8'),
|
||||
];
|
||||
$this->assertTrue(XArray::sequenceEquals($utf8Arr, $utf8->split(new WString('。', 'utf-8'))));
|
||||
}
|
||||
|
||||
public function testChunk(): void {
|
||||
$ndxString = new AString('abcdefghijklmnopqrstuvwxyz');
|
||||
$ndxArray1 = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz'];
|
||||
$ndxArray2 = ['ab', 'cd', 'ef', 'gh', 'ij', 'kl', 'mn', 'op', 'qr', 'st', 'uv', 'wx', 'yz'];
|
||||
$ndxArray3 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||
|
||||
$this->assertTrue(XArray::sequenceEquals($ndxString->chunk(3), $ndxArray1));
|
||||
$this->assertTrue(XArray::sequenceEquals($ndxString->chunk(2), $ndxArray2));
|
||||
$this->assertTrue(XArray::sequenceEquals($ndxString->chunk(1), $ndxArray3));
|
||||
|
||||
$utf8 = new WString('君は実にばかだな', 'utf-8');
|
||||
$ndxArray4 = [
|
||||
new WString('君は実', 'utf-8'),
|
||||
new WString('にばか', 'utf-8'),
|
||||
new WString('だな', 'utf-8'),
|
||||
];
|
||||
$ndxArray5 = [
|
||||
new WString('君は', 'utf-8'),
|
||||
new WString('実に', 'utf-8'),
|
||||
new WString('ばか', 'utf-8'),
|
||||
new WString('だな', 'utf-8'),
|
||||
];
|
||||
$ndxArray6 = [
|
||||
new WString('君', 'utf-8'),
|
||||
new WString('は', 'utf-8'),
|
||||
new WString('実', 'utf-8'),
|
||||
new WString('に', 'utf-8'),
|
||||
new WString('ば', 'utf-8'),
|
||||
new WString('か', 'utf-8'),
|
||||
new WString('だ', 'utf-8'),
|
||||
new WString('な', 'utf-8'),
|
||||
];
|
||||
|
||||
$this->assertTrue(XArray::sequenceEquals($utf8->chunk(3), $ndxArray4));
|
||||
$this->assertTrue(XArray::sequenceEquals($utf8->chunk(2), $ndxArray5));
|
||||
$this->assertTrue(XArray::sequenceEquals($utf8->chunk(1), $ndxArray6));
|
||||
}
|
||||
|
||||
public function testTrim(): void {
|
||||
$ascii = new AString(' meow ');
|
||||
$this->assertTrue($ascii->trim()->equals('meow'));
|
||||
$this->assertTrue($ascii->trimStart()->equals('meow '));
|
||||
$this->assertTrue($ascii->trimEnd()->equals(' meow'));
|
||||
|
||||
$utf16be = $ascii->toWString('utf-16be');
|
||||
$this->assertTrue($utf16be->trim()->equals('meow'));
|
||||
$this->assertTrue($utf16be->trimStart()->equals('meow '));
|
||||
$this->assertTrue($utf16be->trimEnd()->equals(' meow'));
|
||||
|
||||
$utf8 = new WString(' にゃ ', 'utf-8');
|
||||
$this->assertTrue($utf8->trim()->equals(new WString('にゃ', 'utf-8')));
|
||||
$this->assertTrue($utf8->trimStart()->equals(new WString('にゃ ', 'utf-8')));
|
||||
$this->assertTrue($utf8->trimEnd()->equals(new WString(' にゃ', 'utf-8')));
|
||||
}
|
||||
|
||||
public function testCaseChange(): void {
|
||||
$stringMixed = new AString('Sometimes');
|
||||
$stringUpper = new AString('SOMETIMES');
|
||||
$stringLower = new AString('sometimes');
|
||||
|
||||
$this->assertTrue($stringMixed->toUpper()->equals($stringUpper));
|
||||
$this->assertTrue($stringMixed->toLower()->equals($stringLower));
|
||||
}
|
||||
|
||||
public function testEscape(): void {
|
||||
$stringDirty = new AString('<img onerror="alert(\'xss\')">');
|
||||
$stringClean = new AString('<img onerror="alert(\'xss\')">');
|
||||
|
||||
$this->assertTrue($stringDirty->escape()->equals($stringClean));
|
||||
}
|
||||
|
||||
public function testJoin(): void {
|
||||
$ndxString1 = AString::join(['flash', 'wave']);
|
||||
$ndxString2 = AString::join(['Misaka', 'Mikoto'], new AString(' '));
|
||||
|
||||
$this->assertEquals('flashwave', (string)$ndxString1);
|
||||
$this->assertEquals('Misaka Mikoto', (string)$ndxString2);
|
||||
}
|
||||
|
||||
public function testEmpty(): void {
|
||||
$this->assertTrue(XString::nullOrEmpty(null));
|
||||
$this->assertTrue(XString::nullOrEmpty(''));
|
||||
$this->assertTrue(XString::nullOrEmpty(new AString('')));
|
||||
$this->assertFalse(XString::nullOrEmpty('soap'));
|
||||
$this->assertFalse(XString::nullOrEmpty(new AString('boat')));
|
||||
$this->assertTrue(XString::nullOrWhitespace(''));
|
||||
$this->assertTrue(XString::nullOrWhitespace(' '));
|
||||
$this->assertTrue(XString::nullOrWhitespace(new AString(' ')));
|
||||
}
|
||||
|
||||
public function testReverse(): void {
|
||||
$ascii = new AString('Futami Mami');
|
||||
$sjis = new WString("\x91\x6F\x8A\x43\x90\x5E\x94\xFC", 'Shift_JIS');
|
||||
|
||||
$asciiRev = $ascii->reverse();
|
||||
$sjisRev = $sjis->reverse();
|
||||
|
||||
$this->assertEquals('imaM imatuF', (string)$asciiRev);
|
||||
$this->assertEquals("\x94\xFC\x90\x5E\x8A\x43\x91\x6F", (string)$sjisRev);
|
||||
}
|
||||
|
||||
public function testReplace(): void {
|
||||
$ascii = new AString('aiueo');
|
||||
$sjis = new WString("\x82\xA0\x82\xA2\x82\xA4\x82\xA6\x82\xA8", 'sjis');
|
||||
|
||||
$this->assertEquals('aikeo', $ascii->replace('u', 'k'));
|
||||
$this->assertEquals('aeoeo', $ascii->replace('iu', 'eo'));
|
||||
|
||||
$this->assertTrue(
|
||||
$sjis->replace(
|
||||
new WString("\x46\x30", 'utf-16le'),
|
||||
new WString("\xE3\x81\x8B", 'utf-8')
|
||||
)->equals(new WString("\x82\xA0\x82\xA2\x82\xA9\x82\xA6\x82\xA8", 'sjis'))
|
||||
);
|
||||
$this->assertTrue(
|
||||
$sjis->replace(
|
||||
new WString("\xE3\x81\x84\xE3\x81\x86", 'utf-8'),
|
||||
new WString("\x48\x30\x4A\x30", 'utf-16le')
|
||||
)->equals(new WString("\x82\xA0\x82\xA6\x82\xA8\x82\xA6\x82\xA8", 'sjis'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountUnique(): void {
|
||||
$this->assertEquals(10, XString::countUnique('iaabbccddjjefghefghi'));
|
||||
$this->assertEquals(11, (new AString('jeff has three apples'))->countUnique());
|
||||
$this->assertEquals(5, (new WString('みさかみこと'))->countUnique());
|
||||
}
|
||||
}
|
47
tests/WStringTest.php
Normal file
47
tests/WStringTest.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
// WStringTest.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2024-01-04
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Index\WString;
|
||||
|
||||
/**
|
||||
* @covers WString
|
||||
*/
|
||||
final class WStringTest extends TestCase {
|
||||
public function testStartsWith(): void {
|
||||
$this->assertTrue(WString::startsWith('君は実にバカだな', '君は'));
|
||||
}
|
||||
|
||||
public function testEndsWith(): void {
|
||||
$this->assertTrue(WString::endsWith('君は実にバカだな', 'バカだな'));
|
||||
}
|
||||
|
||||
public function testReverse(): void {
|
||||
$this->assertEquals('なだカバに実は君', WString::reverse('君は実にバカだな'));
|
||||
$this->assertEquals("\x82\xc8\x82\xbe\x83\x4a\x83\x6f\x82\xc9\x8e\xc0\x82\xcd\x8c\x4e", WString::reverse("\x8c\x4e\x82\xcd\x8e\xc0\x82\xc9\x83\x6f\x83\x4a\x82\xbe\x82\xc8", encoding: 'Shift_JIS'));
|
||||
}
|
||||
|
||||
public function testTrim(): void {
|
||||
$utf8 = ' にゃ ';
|
||||
$this->assertEquals('にゃ', WString::trim($utf8, encoding: 'utf-8'));
|
||||
$this->assertEquals('にゃ ', WString::trimStart($utf8, encoding: 'utf-8'));
|
||||
$this->assertEquals(' にゃ', WString::trimEnd($utf8, encoding: 'utf-8'));
|
||||
}
|
||||
|
||||
public function testEmpty(): void {
|
||||
$this->assertTrue(WString::nullOrWhitespace(''));
|
||||
$this->assertTrue(WString::nullOrWhitespace(' '));
|
||||
$this->assertTrue(WString::nullOrWhitespace(' '));
|
||||
$this->assertTrue(WString::nullOrWhitespace(' '));
|
||||
}
|
||||
|
||||
public function testCountUnique(): void {
|
||||
$this->assertEquals(10, WString::countUnique('iaabbccddjjefghefghi'));
|
||||
$this->assertEquals(11, WString::countUnique('jeff has three apples'));
|
||||
$this->assertEquals(5, WString::countUnique('みさかみこと'));
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
<?php
|
||||
// XArrayTest.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2022-02-03
|
||||
// Updated: 2024-01-04
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Index\AString;
|
||||
use Index\XArray;
|
||||
|
||||
/**
|
||||
|
@ -75,17 +74,6 @@ final class XArrayTest extends TestCase {
|
|||
$this->assertTrue(XArray::sequenceEquals($array1, $array2));
|
||||
}
|
||||
|
||||
public function testConcat(): void {
|
||||
$ndxString1 = new AString('abcde');
|
||||
$ndxString2 = new AString('a_b_c_d_e');
|
||||
$array = ['a', 'b', 'c', 'd', 'e'];
|
||||
|
||||
$this->assertTrue(AString::join($array)->equals($ndxString1));
|
||||
$this->assertFalse(AString::join($array)->equals($ndxString2));
|
||||
$this->assertFalse(AString::join($array, '_')->equals($ndxString1));
|
||||
$this->assertTrue(AString::join($array, '_')->equals($ndxString2));
|
||||
}
|
||||
|
||||
public function testMerge(): void {
|
||||
$array1 = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||
$array2 = [0, 1, 2, 3];
|
||||
|
|
34
tests/XStringTest.php
Normal file
34
tests/XStringTest.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
// XStringTest.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2024-01-04
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Index\XString;
|
||||
|
||||
/**
|
||||
* @covers XString
|
||||
*/
|
||||
final class XStringTest extends TestCase {
|
||||
public function testEscape(): void {
|
||||
$dirty = '<img onerror="alert(\'xss\')">';
|
||||
$clean = '<img onerror="alert(\'xss\')">';
|
||||
|
||||
$this->assertEquals($clean, XString::escape($dirty));
|
||||
}
|
||||
|
||||
public function testEmpty(): void {
|
||||
$this->assertTrue(XString::nullOrEmpty(null));
|
||||
$this->assertTrue(XString::nullOrEmpty(''));
|
||||
$this->assertFalse(XString::nullOrEmpty('soap'));
|
||||
$this->assertTrue(XString::nullOrWhitespace(''));
|
||||
$this->assertTrue(XString::nullOrWhitespace(' '));
|
||||
}
|
||||
|
||||
public function testCountUnique(): void {
|
||||
$this->assertEquals(10, XString::countUnique('iaabbccddjjefghefghi'));
|
||||
$this->assertEquals(11, XString::countUnique('jeff has three apples'));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue