How to increment letters like numbers in PHP?

后端 未结 8 1380
孤城傲影
孤城傲影 2020-11-27 16:41

I would like to write a function that takes in 3 characters and increments it and returns the newly incremented characters as a string.

I know how to increase a sing

8条回答
  •  甜味超标
    2020-11-27 17:09

    As proposed in PHP RFC: Strict operators directive (currently Under Discussion):

    Using the increment function on a string will throw a TypeError when strict_operators is enabled.

    Whether or not the RFC gets merged, PHP will sooner or later go that direction of adding operator strictness. Therefore, you should not be incrementing strings.

    a-z/A-Z ranges

    If you know your letters will stay in range a-z/A-Z (not surpass z/Z), you can use the solution that converts letter to ASCII code, increments it, and converts back to letter.

    Use ord() a chr():

    $letter = 'A';
    $letterAscii = ord($letter);
    $letterAscii++;
    $letter = chr($letterAscii); // 'B'
    
    1. ord() converts the letter into ASCII num representation
    2. that num representation is incremented
    3. using chr() the number gets converted back to the letter

    As discovered in comments, be careful. This iterates ASCII table so from Z (ASCII 90), it does not go to AA, but to [ (ASCII 91).

    Going beyond z/Z

    If you dare to go further and want z became aa, this is what I came up with:

    final class NextLetter
    {
        private const ASCII_UPPER_CASE_BOUNDARIES = [65, 91];
        private const ASCII_LOWER_CASE_BOUNDARIES = [97, 123];
    
        public static function get(string $previous) : string
        {
            $letters = str_split($previous);
            $output = '';
            $increase = true;
    
            while (! empty($letters)) {
                $letter = array_pop($letters);
    
                if ($increase) {
                    $letterAscii = ord($letter);
                    $letterAscii++;
                    if ($letterAscii === self::ASCII_UPPER_CASE_BOUNDARIES[1]) {
                        $letterAscii = self::ASCII_UPPER_CASE_BOUNDARIES[0];
                        $increase = true;
                    } elseif ($letterAscii === self::ASCII_LOWER_CASE_BOUNDARIES[1]) {
                        $letterAscii = self::ASCII_LOWER_CASE_BOUNDARIES[0];
                        $increase = true;
                    } else {
                        $increase = false;
                    }
    
                    $letter = chr($letterAscii);
                    if ($increase && empty($letters)) {
                        $letter .= $letter;
                    }
                }
    
                $output = $letter . $output;
            }
    
            return $output;
        }
    }
    

    I'm giving you also 100% coverage if you intend to work with it further. It tests against original string incrementation ++:

        /**
         * @dataProvider letterProvider
         */
        public function testIncrementLetter(string $givenLetter) : void
        {
            $expectedValue = $givenLetter;
    
            self::assertSame(++$expectedValue, NextLetter::get($givenLetter));
        }
    
        /** 
         * @return iterable>
         */
        public function letterProvider() : iterable
        {
            yield ['A'];
            yield ['a'];
            yield ['z'];
            yield ['Z'];
            yield ['aaz'];
            yield ['aaZ'];
            yield ['abz'];
            yield ['abZ'];
        }
    

提交回复
热议问题