converting from base 10 to base 31 (working only with select characters)
I'd like to convert base 10 numbers to base 31
I would like to use only these characters: 23456789abcdefghjkmnpqrstuvwxyz
As you can see, 5 characters are excluded (i don't need these): 1 0 o l i
The function I have now 开发者_如何学编程is below but of course it doesn't work. When 2 is input it outputs 4. The output for tenTo31(2)
should be 2
function tenTo31($num)
{
$out = "";
$alpha = "23456789abcdefghjkmnpqrstuvwxyz";
while($num > 30)
{
$r = $num % 31;
$num = floor($num / 31) - 1;
$out = $alpha[$r] . $out;
}
return $alpha[$num] . $out;
}
Any ideas on how to make this work?
This is a blind guess at what you want:
$alpha = "yz23456789abcdefghjkmnpqrstuvwx";
There's a built-in function for converting from one base to another, base_convert(). The alphabet is fixed, but you can use strtr() to replace those digits with your own.
"The output for tenTo31(2) should be 2": One possibility is to make '2' the third symbol again.
function tenTo31($num) {
static $from = "0123456789abcdefghijklmnopqrstu";
static $to = "yz23456789abcdefghjkmnpqrstuvwx";
return strtr(base_convert($num, 10, 31), $from, $to);
}
for($i=0; $i<31; $i++) {
echo $i, '=', tenTo31($i), ' | ';
if ( 9===$i%10 ) echo "\n";
}
prints
0=y | 1=z | 2=2 | 3=3 | 4=4 | 5=5 | 6=6 | 7=7 | 8=8 | 9=9 |
10=a | 11=b | 12=c | 13=d | 14=e | 15=f | 16=g | 17=h | 18=j | 19=k |
20=m | 21=n | 22=p | 23=q | 24=r | 25=s | 26=t | 27=u | 28=v | 29=w |
30=x |
edit: To convert the base(31) number back to decimal you first have to reverse the translation (strtr) and then call base_convert(.., 31, 10). You can combine the conversion from and to base(31) in a single function.
function convert_ten_31($num, $numIsDecimal) {
static $default = "0123456789abcdefghijklmnopqrstu";
static $symbols = "yz23456789abcdefghjkmnpqrstuvwx";
if ( $numIsDecimal ) {
return strtr(base_convert($num, 10, 31), $default, $symbols);
}
else {
return base_convert(strtr($num, $symbols, $default), 31, 10);
}
}
// testing
for($i=0; $i<10000; $i++) {
$x = convert_ten_31($i, true);
$x = convert_ten_31($x, false);
if ( $i!==(int)$x ) {
var_dump($i, $x);
die;
}
}
echo 'done.';
It's also easily possible to write a function like base_convert() yourself that take the symbols as parameter and thus having one flexible function instead of tenTo30(), tenTo31(), tenTo32(), ....
You aren't using the 1 and 0 characters, the first digit in your numbering system is 2 meaning 2 is the equivalent of 0 in base 10. 3 is equivalent to 1 in base 10 and 4 is equivalent to 2 in base 10.
Why are you taking modules by 32? You should use %31 and /31. In base 10 we are using modules by 10, so should be in base 31. But if we forget about this, I think your logic is correct. I can't understand why 2 in base 10 is equal to 4 in base 31 using your "modified digits".
While I'd encourage you to continue along with your algorithm for the learning exercise, consider using base_convert if you just need to get the job done.
The mapping according to http://www.crockford.com/wrmg/base32.html appears to be:
function symbolToEncode ($num) {
$out = "";
static $alpha = "0123456789ABCDEFGHJKMNPQRSTVWXYZ*~$=U";
while ($num >= 37) {
$r = $num % 37;
$num = floor ($num / 37);
$out = $out . $alpha[$r];
}
return $out . $alpha[$num];
}
function decodeToEncode ($str) {
static $from = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*~=$";
static $to = "0123456789ABCDEFGH1JK1MN0PQRSTUVWXYZABCDEFGH1JK1MN0PQRSTUVWXYZ*~=$";
return strtr ($str, $from, $to);
}
Though clearly the real challenge is to write a encodeToSymbol() function. I am not really a PHP expert (my $'s in the strings probably needs to be escaped somehow -- hints?), so I will leave that to others.
精彩评论