简体   繁体   中英

How to increment an alphanumeric string in PHP?

There's a string, containing characters [a-zA-Z0-9] . This should be 26 * 2 + 10 = 62 possibilities in one character and 62^2 in two. What is the preferred way to increment a value of such a string, so that 'aA', becomes 'aB', etc.? Is there any built-in stuff in PHP, that can help?

I know you can increment a string, but that's only lowercase letters. Essentially, the result should go from 'a' to 'aa' in 61 increments.

Try this function:

<?php
function increment(&$string){
    $last_char=substr($string,-1);
    $rest=substr($string, 0, -1);
    switch ($last_char) {
    case '':
        $next= 'a';
        break;
    case 'z':
        $next= 'A';
        break;
    case 'Z':
        $next= '0';
        break;
    case '9':
        increment($rest);
        $next= 'a';
        break;
    default:
        $next= ++$last_char;
    }
    $string=$rest.$next;
}

    //sample
    $string='a';
    for($i=1;$i<=128;$i++){
        echo $string."<br>";
        increment($string);
    }
    ?>

This works for me:

<?php
$str = 'a';
echo ++$str; // b

$str = 'z';
echo ++$str; // aa

$str = 'aA';
echo ++$str; // aB

The @simshaun dont work for me. I check the documentation and I found base_convert that can work for you (on base 35) and a comment of " francesco[at]paladinux.net " with a function to work on base65.

so the solution can be:

convert to b10 -> increment +1 -> convert base 65

EDIT 1

talking about convert I think to base64 coding so I wrote this 2 funcs using base64 encode/decode numbers. Unfortunately the charset used is a bit larger: [a-zA-Z0-9/+=], but using an internal function more efficent.

The Zero 0 is "AA=="

function nencode($in){
        $res ="";
        while(1){
                $b = $in & 0xff;
                $res = chr($b) . $res;

                if($in > 0xff){
                        $in = $in >> 8;
                } else {
                        break;
                }
        }
        return base64_encode($res);
}

function ndecode($in){

        $rv=0;
        $res =base64_decode($in);
        for($t = 0 ; $t < strlen($res) ; $t++){
                if($t>0){
                        $rv = $rv << 8;
                }
                $c = ord($res{$t});
                $rv |= $c;
        }
        return $rv;
}

I like this one. How to use: ClassX::increment('p04E7K', 6); ClassX::decrement('p04E7K', 6);

Code:

class ClassX {
    public static $baseCharacters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static function increment($x, $digits)
    {
        $charList = static::$baseCharacters;

        // completa cadeia de caracteres com o numero de digitos parametrizados
        $x = trim($x);
        if(strlen($x) < $digits) {
            $x = str_pad($x, $digits, substr($charList, 0, 1), STR_PAD_LEFT);
        }

        $result = preg_split("//", $x, -1, PREG_SPLIT_NO_EMPTY);
        // percorre a cadeia de caracteres de tras pra frente e incrementa o primeiro caractere possivel
        for ($i = $digits - 1; $i >= 0; --$i)
        {
            $char = $result[$i];
            $currentChar = strpos($charList, $char);
            $nextCharPosition = $currentChar+1;

            if($nextCharPosition < strlen($charList)) {
                $nextChar = substr($charList, $nextCharPosition, 1);

                $result[$i] = $nextChar;
                break;
            }
        }

        return implode('', $result);
    }

    public static function decrement($x, $digits)
    {
        $charList = static::$baseCharacters;

        // completa cadeia de caracteres com o numero de digitos parametrizados
        if(strlen($x) < $digits) {
            $x = str_pad($x, $digits, substr($charList, 0, 1), STR_PAD_LEFT);
        }

        $result = preg_split("//", $x, -1, PREG_SPLIT_NO_EMPTY);
        // percorre a cadeia de caracteres de tras pra frente e decrementa o primeiro caractere possivel
        for ($i = $digits - 1; $i >= 0; --$i)
        {
            $char = $result[$i];
            $currentChar = strpos($charList, $char);
            $previousCharPosition = $currentChar-1;

            if($previousCharPosition > -1) {
                $previousChar = substr($charList, $previousCharPosition, 1);

                $result[$i] = $previousChar;

                // define os caracteres apos o decrementado para o ultimo caractere. ex: 3[00] > 2[99]
                for ($j = $i + 1; $j < $digits && $i < $digits - 1; ++$j)
                    $result[$j] = substr($charList, strlen($charList)-1, 1);
                break;
            }
        }

        return implode('', $result);
    }
}

I came to this question as I was looking also for a way to generate auto incrementing alphanumeric unique ID very similar to what we have in mobile money(M-PESA) in Kenya. For reference, here is a screenshot showing the transactions Screenshot showing sample MPESA transactions I'd like to leave it here if anyone is looking also for similar properties: ie - Autoincrement alphanumeric - All characters in uppercase - automatic increase of string length once exhausted. - the increment is from 0 to 9 then A to Z before incrementing the adjacent character of number and is a modification of @phobia82's answer

function increment($string){
    $last_char=substr($string,-1);
    $rest=substr($string, 0, -1);
    switch ($last_char) {
        case '':
            $next= 'A';
            break;
        case 'Z':
            $next = '0';
            $unique = increment($rest);
            $rest = $unique;
            break;
        case '9':
            $next= 'A';
            break;
        default:
            $next = ++$last_char;
            break;
    }
    $string=$rest.$next;
    return $string;
}

I think that this fundamentally does what you're after.

<?php

$chars = array('', 
    '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',
    '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',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');

$increment1 = 0;
$increment2 = 0;

for ($i = 0; $i <= 200; $i++) {
    if ($increment2 === 62) {
        $increment1++;
        $increment2 = 1;
    } else {
        $increment2++;
    }
    echo "{$chars[$increment1]}{$chars[$increment2]} ";
}

/*
Output:
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 
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 
0 1 2 3 4 5 6 7 8 9 aa ab ac ad ae af ag ah ai aj ak al
am an ao ap aq ar as at au av aw ax ay az aA aB aC aD aE 
aF aG aH aI aJ aK aL aM aN aO aP aQ aR aS aT aU aV aW aX 
aY aZ a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 ba bb bc bd be bf bg 
bh bi bj bk bl bm bn bo bp bq br bs bt bu bv bw bx by bz 
bA bB bC bD bE bF bG bH bI bJ bK bL bM bN bO bP bQ bR bS 
bT bU bV bW bX bY bZ b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ca cb 
cc cd ce cf cg ch ci cj ck cl cm cn co
*/

This is my approach. We iterate backward from the end of the string and increment each character based on $characters . There's no need to split or implode since each character position can be referenced directly by it's index and this is very fast.

This function will loop based on the string length, so if we pass ZZ it will then reset back to 00 . If instead you want to continue adding digits so that ZZ become 100 you can set $loop to false :

function increment($x, $loop = true) {
    $chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $char_count = strlen($chars);
    $c = strlen($x);
    for ($i = $c - 1; $i >= 0; --$i) {
        $pos = strpos($chars, $x[$i]) + 1;
        $pos = $pos < $char_count ? $pos : 0;
        $x[$i] = $chars[$pos];
        if ($pos > 0) break;
        if (!$loop && !$i && !$pos) $x = $chars[1] . $x;
    }
    return $x;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM