Skip to content

Commit

Permalink
Str::chr() without iconv
Browse files Browse the repository at this point in the history
  • Loading branch information
paranoiq committed Jul 22, 2022
1 parent 2712a03 commit 309a721
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/common/Str.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
use Error;
use Nette\Utils\Strings;
use UConverter;
use function ord;
use const MB_CASE_TITLE;
use function array_keys;
use function array_pop;
use function array_shift;
use function array_values;
use function chr;
use function class_exists;
use function count;
use function error_clear_last;
Expand All @@ -42,6 +42,7 @@
use function mb_strtoupper;
use function mb_substr;
use function min;
use function ord;
use function range;
use function str_replace;
use function strcasecmp;
Expand Down Expand Up @@ -76,7 +77,25 @@ public static function fixEncoding(string $string): string

public static function chr(int $code): string
{
return Strings::chr($code);
if ($code < 0 || ($code >= 0xD800 && $code <= 0xDFFF) || $code > 0x10FFFF) {
throw new InvalidValueException($code, 'unicode codepoint in range 0x00 to 0xD7FF or 0xE000 to 0x10FFFF');
}

if ($code <= 0x7F) {
return chr($code); // 0-7,0-F
} elseif ($code <= 0x7FF) {
return chr(0b11000000 + ($code >> 6)) // 0xC-D,0-F,8-B,0-9
. chr(128 + ($code & 63));
} elseif ($code <= 0xFFFF) {
return chr(0b11100000 + ($code >> 12)) // 0xE,0-F,8-B,0-9,8-B,0-9
. chr(128 + (($code >> 6) & 63))
. chr(128 + ($code & 63));
} else {
return chr(0b11110000 + ($code >> 18)) // 0xF,0-7,8-B,0-9,8-B,0-9,8-B,0-9
. chr(128 + (($code >> 12) & 63))
. chr(128 + (($code >> 6) & 63))
. chr(128 + ($code & 63));
}
}

public static function ord(string $ch): int
Expand Down
35 changes: 35 additions & 0 deletions tests/src/common/Str.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,46 @@

namespace Dogma\Tests\Str;

use Dogma\InvalidValueException;
use Dogma\Str;
use Dogma\Tester\Assert;

require_once __DIR__ . '/../bootstrap.php';

chr:
Assert::same(Str::chr(0x000000), "\x00");
Assert::same(Str::chr(0x00007F), "\x7F");
Assert::same(Str::chr(0x000080), "\u{80}");
Assert::same(Str::chr(0x0007FF), "\u{7FF}");
Assert::same(Str::chr(0x000800), "\u{800}");
Assert::same(Str::chr(0x00D7FF), "\u{D7FF}");
Assert::same(Str::chr(0x00E000), "\u{E000}");
Assert::same(Str::chr(0x00FFFF), "\u{FFFF}");
Assert::same(Str::chr(0x010000), "\u{10000}");
Assert::same(Str::chr(0x10FFFF), "\u{10FFFF}");

foreach ([-1, 0xD800, 0xDFFF, 0x110000] as $code) {
Assert::exception(
static function() use ($code): void {
Str::chr($code);
},
InvalidValueException::class
);
}


ord:
Assert::same(Str::ord("\x00"), 0x000000);
Assert::same(Str::ord("\x7F"), 0x00007F);
Assert::same(Str::ord("\u{80}"), 0x000080);
Assert::same(Str::ord("\u{7FF}"), 0x0007FF);
Assert::same(Str::ord("\u{800}"), 0x000800);
Assert::same(Str::ord("\u{D7FF}"), 0x00D7FF);
Assert::same(Str::ord("\u{E000}"), 0x00E000);
Assert::same(Str::ord("\u{FFFF}"), 0x00FFFF);
Assert::same(Str::ord("\u{10000}"), 0x010000);
Assert::same(Str::ord("\u{10FFFF}"), 0x10FFFF);


between:
Assert::same(Str::between('abc@def#ghi', '@', '#'), 'def');
Expand Down

0 comments on commit 309a721

Please sign in to comment.