How to increment letters like numbers in PHP?

2020-01-24 21:09发布

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 single letter to the next one but how would I know when to increase the second letters and then stop and then increase the first letter again to have a sequential increase?

So if AAA is passed, return AAB. If AAZ is passed return ABA (hard part).

I would appreciate help with the logic and what php functions will be useful to use.

Even better, has some done this already or there is a class available to do this??

Thanks all for any help

标签: php
8条回答
甜甜的少女心
2楼-- · 2020-01-24 21:30

You could use the ASCII codes for alpha numerics. From there you increment and decrement to get the previous/next character.

You could split your string in single characters and then apply the transformations on these characters.

Just some thoughts to get you started.

查看更多
叼着烟拽天下
3楼-- · 2020-01-24 21:42

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<string>
     */
    public function letterProvider() : iterable
    {
        yield ['A'];
        yield ['a'];
        yield ['z'];
        yield ['Z'];
        yield ['aaz'];
        yield ['aaZ'];
        yield ['abz'];
        yield ['abZ'];
    }
查看更多
可以哭但决不认输i
4楼-- · 2020-01-24 21:49

Character/string increment works in PHP (though decrement doesn't)

$x = 'AAZ';
$x++;
echo $x;
查看更多
狗以群分
5楼-- · 2020-01-24 21:49

You can do it with the ++ operator.

$i = 'aaz';
$i++;
print $i;

aba

However this implementation has some strange things:

for($i = 'a'; $i < 'z'; $i++) print "$i ";

This will print out letters from a to y.

for($i = 'a'; $i <= 'z'; $i++) print "$i ";

This will print out lettes from a to z and it continues with aa and ends with yz.

查看更多
爷的心禁止访问
6楼-- · 2020-01-24 21:51
 <?php 
$values[] = 'B';
$values[] = 'A';
$values[] = 'Z';
foreach($values as $value ){
  if($value == 'Z'){ 
       $value = '-1';
    }
$op = ++$value;
echo $op;
}
?>
查看更多
Bombasti
7楼-- · 2020-01-24 21:52

To increment or decrement in the 7bits 128 chars ASCII range, the safest:

$CHAR = "l";
echo chr(ord($CHAR)+1)." ".chr(ord($CHAR)-1);
/* m k */

So, it is normal to get a backtick by decrementing a, as the ascii spec list

Print the whole ascii range:

for ($i = 0;$i < 127;$i++){
    echo chr($i);
}
/* !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ */

More infos about ANSI 7 bits ASCII: man ascii


To increment or decrement in the 8-bits extended 256 chars UTF-8 range.

This is where it starts to differ regarding the host machine charset. but those charsets are all available on modern machines. From php, the safest is to use the php-mbstring extension: https://www.php.net/manual/en/function.mb-chr.php

Extended ASCII (EASCII or high ASCII) character encodings are eight-bit or larger encodings that include the standard seven-bit ASCII characters, plus additional characters. https://en.wikipedia.org/wiki/Extended_ASCII

More info, as example: man iso_8859-9

   ISO 8859-1    West European languages (Latin-1)
   ISO 8859-2    Central and East European languages (Latin-2)
   ISO 8859-3    Southeast European and miscellaneous languages (Latin-3)
   ISO 8859-4    Scandinavian/Baltic languages (Latin-4)
   ISO 8859-5    Latin/Cyrillic
   ISO 8859-6    Latin/Arabic
   ISO 8859-7    Latin/Greek
   ISO 8859-8    Latin/Hebrew
   ISO 8859-9    Latin-1 modification for Turkish (Latin-5)
   ISO 8859-10   Lappish/Nordic/Eskimo languages (Latin-6)
   ISO 8859-11   Latin/Thai
   ISO 8859-13   Baltic Rim languages (Latin-7)
   ISO 8859-14   Celtic (Latin-8)
   ISO 8859-15   West European languages (Latin-9)
   ISO 8859-16   Romanian (Latin-10)

Example, we can find the symbol in ISO 8859-7:

244   164   A4     €     EURO SIGN

To increment or decrement in the 16 bits UTF-16 Unicode range:

Here is a way to generate the whole unicode charset, by generating html entities and converting to utf8. Run it online

for ($x = 0; $x < 262144; $x++){
  echo html_entity_decode("&#".$x.";",ENT_NOQUOTES,"UTF-8");
}

Same stuff, but the range goes up to (16^4 * 4)!

echo html_entity_decode('&#33;',ENT_NOQUOTES,'UTF-8');
/* ! */
echo html_entity_decode('&#34;',ENT_NOQUOTES,'UTF-8');
/* " */

To retrieve the unicode symbol,using the base10 decimal representation of the character.

echo html_entity_decode('&#8364;',ENT_NOQUOTES,'UTF-8');
/* € */

The same symbol, using the base16 hexadecimal representation:

echo html_entity_decode('&#'.hexdec("20AC").';',ENT_NOQUOTES,'UTF-8');
/* € */

First 32 bits are reserved for special control characters, output garbage �����, but have a meaning.

查看更多
登录 后发表回答