PDA

View Full Version : Auto-increment alphanumeric characters in PHP


Lincoln
29 Apr 2009, 7:21pm
Anyone know how to auto-increment alphanumeric characters for a URL-shortener in PHP?

Instead of counting up from zero, I'd want it to count up from 0-9 and then a-z. Then it would be 00-09 to 0a-0z, and then to 10-19 to 1a-1z, and so on.

MiracleManS
29 Apr 2009, 7:50pm
BIT-WISE ASCII ENCODES!?!!!!!!


Edit: Now to be serious...

Convert the string to a decimal, add one, then turn it back into ascii...

pragtastic
29 Apr 2009, 9:47pm
MMS: What happens when you add 1 to z? You're gonna go off the end of your range and get some ascii value that you don't want.

This might be the long/tedious route, but probably how I'd go about it if you can't find something out there for this already:

Setup a mapping that correlates 0-9a-z to 0-35, maybe in a method that takes a single character and returns the int (sadly this would probably be a 36 case switch statement).
Then break your alphanumeric string into single character and load those into an array. Try to increment the last element of the array by 1 and do a mod operation on the sum by 36 ( newVal = (val +1) % 36). If your newVal is then a 0 (you rolled over), then you need to go back another element in the array and repeat the process. If you roll over all the values in the array, then you tack a 0 on to all the other 0's in the array. Once the operation is done, collect your integers, run them through the mapping in reverse and concat them back into a string.

pragtastic
29 Apr 2009, 9:59pm
Other thoughts...

I presume you're using 0-9a-z because it'll keep the url smaller for a longer duration (versus something like a simple 0-9 system). If you're going for something that, have you considered using UpperCase letters as well, so 0-9a-zA-Z? Giving 62 characters to work with instead of 36.

shwaip
29 Apr 2009, 10:04pm
don't know how to use php, but:

use an int counter;



digone = counter (mod) 36^5
digtwo = counter (mod) 36^4
digthree = counter (mod) 36^3
digfour = counter (mod) 36^2
digfive = counter (mod) 36

char out = convertToChar(input) {
out = 0;
if(input) < 10 {
out = input + 48;
} else {
out = input + 87;
}
}


then concat all the individual chars

shwaip
29 Apr 2009, 10:06pm
and you could totally do that in some sort of cool for loop.

shwaip
29 Apr 2009, 10:07pm
and if you wanted to restrict yourself to 32 chars, you could do it with some bit-shifting, rather than mod operations.


ttttttt-riple post

Lincoln
29 Apr 2009, 10:14pm
Yeah, I'll probably do something like MiracleMan or prag described; split it up, convert to a numeric representation, increment, boundary check it, convert back to the equivalent alphanumerics, and concat back together. Ugh.
have you considered using UpperCase letters as well, so 0-9a-zA-Z?Domain names are case-insensitive. While you can make the rest of the URL case-sensitive, it's not expected behavior. People expect, for instance, that http://twitter.com/Icrontic and http://twitter.com/icrontic are the same thing. The potential confusion isn't worth the saved characters.
don't know how to use php, but:
use an int counter;
then concat all the individual chars
You done gone lost me. :-/

//edit: shwaip, PHP is super-low-level; there's no strict variable typing, required declarations, or playing with bits. I can't even remember what mod does; I only had an intro C++ course (I assume that's what that was).

shwaip
29 Apr 2009, 10:28pm
Also, I ninja edited the code a little.

mod (%) is basically remainder. 1234 % 1000 = 234;

i re-wrote code below in a better way.

and so on.

the chr() function converts the ascii value to a character

pragtastic
29 Apr 2009, 10:36pm
//edit: shwaip, PHP is super-low-level; there's no strict variable typing, required declarations, or playing with bits. I can't even remember what mod does; I only had an intro C++ course (I assume that's what that was).

I would say loose typing makes a language more high-level than low-level ;)

shwaip
29 Apr 2009, 10:39pm
wow my code is wrong - new code:



for($counter=0; $counter < HUEG; $counter++){ #this would be the global_index for all your articles
$shortURL ="";
$tmp_count = $counter;
for($i=URL_LEN; $i > 0; $i--){ #URL_LEN is the desired length of url
$tmp = floor($tmp_count/(36^$i));
$tmp_count -= $tmp*(36^$i);
if($tmp < 10) {
$shortURL .= chr($tmp + 48);
} else {
$shortURL .= chr($tmp + 87);
}
}
}

pragtastic
29 Apr 2009, 10:40pm
shwaip: nice use of powers(36^$i), I wouldn't have thought of that.

MiracleManS
29 Apr 2009, 10:41pm
MMS: What happens when you add 1 to z? You're gonna go off the end of your range and get some ascii value that you don't want.

I didn't know I had to prescribe the ENTIRE idea and code it for him :tongue:

pragtastic
29 Apr 2009, 10:56pm
shwaip did the heavy lifting :P

Lincoln
29 Apr 2009, 10:57pm
OK, but there won't be a static URL length; it'll grow with necessity (starting at 1 character), not stay fixed at a particular length.

So then 36^URL_LEN >= the integer key (HUEG), right? Then I could run this bit before yours:


$a = HUEG;
$URL_LEN = 1;
while ( $a > 36 ) {
$a = $a/36;
$URL_LEN++;
}

shwaip
29 Apr 2009, 11:00pm
a few examples - obviously, you'd increment by 1 for IC articles/links.:
http://students.washington.edu/hanusaem/test.php

source:
http://students.washington.edu/hanusaem/test.txt

shwaip
29 Apr 2009, 11:05pm
hmm the code is still not quite right.

Yes, if you want to have a variable length url, that is how you would do it.

edit: So, this looks like it's working now:



<?php

for($counter=0; $counter < 10000; $counter+=1) {
$shorturl = "";
$tmp_count = $counter;
for($i=5;$i>=0; $i--) {
$tmp = floor($tmp_count/pow(36,$i));
$tmp_count -= $tmp*pow(36,$i);
if($tmp < 10) {
$shorturl .= chr($tmp + 48);
} else {
$shorturl .= chr($tmp + 87);
}
}
}
?>