diff --git a/src/Encoder/Encoder.php b/src/Encoder/Encoder.php index c363953..6a7a951 100644 --- a/src/Encoder/Encoder.php +++ b/src/Encoder/Encoder.php @@ -25,6 +25,11 @@ final class Encoder /** @deprecated use DEFAULT_BYTE_MODE_ENCODING */ public const DEFAULT_BYTE_MODE_ECODING = self::DEFAULT_BYTE_MODE_ENCODING; + /** + * Allowed characters for the Alphanumeric Mode. + */ + private const ALPHANUMERIC_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'; + /** * The original table is defined in the table 5 of JISX0510:2004 (p.19). */ @@ -148,13 +153,9 @@ public static function encode( /** * Gets the alphanumeric code for a byte. */ - private static function getAlphanumericCode(int $code) : int + private static function getAlphanumericCode(int $byte) : int { - if (isset(self::ALPHANUMERIC_TABLE[$code])) { - return self::ALPHANUMERIC_TABLE[$code]; - } - - return -1; + return self::ALPHANUMERIC_TABLE[$byte] ?? -1; } /** @@ -162,30 +163,20 @@ private static function getAlphanumericCode(int $code) : int */ private static function chooseMode(string $content, ?string $encoding = null) : Mode { + if ('' === $content) { + return Mode::BYTE(); + } + if (null !== $encoding && 0 === strcasecmp($encoding, 'SHIFT-JIS')) { return self::isOnlyDoubleByteKanji($content) ? Mode::KANJI() : Mode::BYTE(); } - $hasNumeric = false; - $hasAlphanumeric = false; - $contentLength = strlen($content); - - for ($i = 0; $i < $contentLength; ++$i) { - $char = $content[$i]; - - if (ctype_digit($char)) { - $hasNumeric = true; - } elseif (-1 !== self::getAlphanumericCode(ord($char))) { - $hasAlphanumeric = true; - } else { - return Mode::BYTE(); - } + if (ctype_digit($content)) { + return Mode::NUMERIC(); } - if ($hasAlphanumeric) { + if (self::isOnlyAlphanumeric($content)) { return Mode::ALPHANUMERIC(); - } elseif ($hasNumeric) { - return Mode::NUMERIC(); } return Mode::BYTE(); @@ -205,7 +196,7 @@ private static function calculateMaskPenalty(ByteMatrix $matrix) : int } /** - * Checks if content only consists of double-byte kanji characters. + * Checks if content only consists of double-byte kanji characters (or is empty). */ private static function isOnlyDoubleByteKanji(string $content) : bool { @@ -232,6 +223,14 @@ private static function isOnlyDoubleByteKanji(string $content) : bool return true; } + /** + * Checks if content only consists of alphanumeric characters (or is empty). + */ + private static function isOnlyAlphanumeric(string $content) : bool + { + return strlen($content) === strspn($content, self::ALPHANUMERIC_CHARS); + } + /** * Chooses the best mask pattern for a matrix. */ diff --git a/test/Encoder/EncoderTest.php b/test/Encoder/EncoderTest.php index 66459e9..bc90c7e 100644 --- a/test/Encoder/EncoderTest.php +++ b/test/Encoder/EncoderTest.php @@ -63,6 +63,10 @@ public function testGetAlphanumericCode() : void public function testChooseMode() : void { + // Empty string + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '')); + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '', 'SHIFT-JIS')); + // Numeric mode $this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0')); $this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0123456789')); @@ -77,7 +81,6 @@ public function testChooseMode() : void // 8-bit byte mode $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, 'a')); $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '#')); - $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '')); // AIUE in Hiragana in SHIFT-JIS $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6"));