number convert php math base-conversion

number - base convert php



Conversión de base de números de tamaño arbitrario(PHP) (3)

Tengo una larga "cadena binaria" como la salida de la función de paquete de PHP.

¿Cómo puedo convertir este valor a base62 (0-9a-zA-Z)? Las funciones matemáticas incorporadas se desbordan con entradas tan largas, y BCmath no tiene una función base_convert, ni nada que sea específico. También necesitaría una función "pack base62" correspondiente.


A menos que realmente, realmente tengas que tener base62, ¿por qué no ir por:

base64_encode() base64_decode()

Los únicos otros caracteres añadidos son "+" y "=", y es un método muy conocido para empacar y descomprimir cadenas binarias con funciones disponibles en muchos otros idiomas.


Aquí hay una función base_conv() que puede convertir bases completamente arbitrarias, expresadas como matrices de cadenas; Cada elemento de la matriz representa un único "dígito" en esa base, lo que también permite valores de múltiples caracteres (es su responsabilidad evitar la ambigüedad).

function base_conv($val, &$baseTo, &$baseFrom) { return base_arr_to_str(base_conv_arr(base_str_to_arr((string) $val, $baseFrom), count($baseTo), count($baseFrom)), $baseTo); } function base_conv_arr($val, $baseToDigits, $baseFromDigits) { $valCount = count($val); $result = array(); do { $divide = 0; $newlen = 0; for ($i = 0; $i < $valCount; ++$i) { $divide = $divide * $baseFromDigits + $val[$i]; if ($divide >= $baseToDigits) { $val[$newlen ++] = (int) ($divide / $baseToDigits); $divide = $divide % $baseToDigits; } else if ($newlen > 0) { $val[$newlen ++] = 0; } } $valCount = $newlen; array_unshift($result, $divide); } while ($newlen != 0); return $result; } function base_arr_to_str($arr, &$base) { $str = ''''; foreach ($arr as $digit) { $str .= $base[$digit]; } return $str; } function base_str_to_arr($str, &$base) { $arr = array(); while ($str === ''0'' || !empty($str)) { foreach ($base as $index => $digit) { if (mb_substr($str, 0, $digitLen = mb_strlen($digit)) === $digit) { $arr[] = $index; $str = mb_substr($str, $digitLen); continue 2; } } throw new Exception(); } return $arr; }

Ejemplos:

$baseDec = str_split(''0123456789''); $baseHex = str_split(''0123456789abcdef''); echo base_conv(255, $baseHex, $baseDec); // ff echo base_conv(''ff'', $baseDec, $baseHex); // 255 // multi-character base: $baseHelloworld = array(''hello '', ''world ''); echo base_conv(37, $baseHelloworld, $baseDec); // world hello hello world hello world echo base_conv(''world hello hello world hello world '', $baseDec, $baseHelloworld); // 37 // ambiguous base: // don''t do this! base_str_to_arr() won''t know how to decode e.g. ''11111'' // (well it does, but the result might not be what you''d expect; // It matches digits sequentially so ''11111'' would be array(0, 0, 1) // here (matched as ''11'', ''11'', ''1'' since they come first in the array)) $baseAmbiguous = array(''11'', ''1'', ''111'');


Creo que hay un malentendido detrás de esta pregunta. La conversión de base y la codificación / decodificación son diferentes . La salida de base64_encode(...) no es un número base64 grande. Es una serie de valores base64 discretos, que corresponden a la función de compresión. Es por eso que BC Math no funciona, porque BC Math se preocupa por los números grandes solos, no por las cadenas que son en realidad grupos de números pequeños que representan datos binarios.

Aquí hay un ejemplo para ilustrar la diferencia:

base64_encode(1234) = "MTIzNA==" base64_convert(1234) = "TS" //if the base64_convert function existed

la codificación base64 divide la entrada en grupos de 3 bytes (3 * 8 = 24 bits), luego convierte cada subsegmento de 6 bits (2 ^ 6 = 64, por lo tanto, "base64") en el carácter base64 correspondiente (los valores son " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 + / ", donde A = 0, / = 63).

En nuestro ejemplo, base64_encode() considera "1234" como una cadena de 4 caracteres, no un número entero (porque base64_encode() no opera en enteros). Por lo tanto, muestra "MTIzNA ==", porque (en US-ASCII / UTF-8 / ISO-8859-1) "1234" es 00110001 00110010 00110011 00110100 en formato binario. Esto se divide en 001100 (12 en decimal, carácter "M") 010011 (19 en decimal, carácter "T") 001000 ("I") 110011 ("z") 001101 ("N") 00. Desde el último grupo no está completo, se rellena con 0 y el valor es 000000 ("A"). Como todo está hecho por grupos de 3 caracteres de entrada, hay 2 grupos: "123" y "4". El último grupo está rellenado con = para que tenga 3 caracteres de largo, por lo que toda la salida se convierte en "MTIzNA ==".

la conversión a base64 , por otro lado, toma un único valor entero y lo convierte en un único valor base64. Para nuestro ejemplo, 1234 (decimal) es "TS" (base64), si usamos la misma cadena de valores base64 que arriba. Trabajando hacia atrás y de izquierda a derecha: T = 19 (columna 1), S = 18 (columna 0), entonces (19 * 64 ^ 1) + (18 * 64 ^ 0) = 19 * 64 + 18 = 1234 (decimal). El mismo número se puede representar como "4D2" en hexadecimal (base16): (4 * 16 ^ 2) + (D * 16 ^ 1) + (2 * 16 ^ 0) = (4 * 256) + (13 * 16) ) + (2 * 1) = 1234 (decimal).

A diferencia de la codificación , que toma una cadena de caracteres y la cambia, la conversión base no altera el número real, solo cambia su presentación. El hexadecimal (base16) "FF" es el mismo número que el decimal (base10) "255", que es el mismo número que "11111111" en binario (base2). Piense en ello como el cambio de divisas, si la tasa de cambio nunca cambió: $ 1 USD tiene el mismo valor que £ 0,79 GBP (tipo de cambio a partir de hoy, pero pretende que nunca cambia).

En informática, los enteros normalmente se utilizan como valores binarios (porque es fácil construir unidades aritméticas de 1 bit y luego juntarlas para formar unidades aritméticas de 32 bits / etc. Para hacer algo tan simple como "255 + 255" (decimal), la computadora primero necesita convertir los números a binarios ("11111111" + "11111111") y luego realizar la operación en la Unidad de lógica aritmética (ALU).

Casi todos los demás usos de las bases son puramente para la conveniencia de los humanos (presentación): las computadoras muestran su valor interno 11111111 (binario) como 255 (decimal) porque los humanos están entrenados para operar con números decimales. La función base64_convert() no existe como parte del repertorio estándar de PHP porque a menudo no es útil para nadie: no muchos humanos leen números base64 de forma nativa. Por el contrario, los 1 y 0 binarios a veces son útiles para programadores (¡podemos usarlos como interruptores on / off!), Y el hexadecimal es conveniente para humanos que editan datos binarios porque un byte completo de 8 bits puede representarse sin ambigüedad como 00 a FF, sin perder demasiado espacio.

Puede preguntar, "si la conversión de base es solo para presentación, ¿por qué existe BC Math?" Esa es una pregunta justa, y también exactamente por qué dije "casi" puramente para presentación: las computadoras típicas están limitadas a números de 32 o 64 bits de ancho, que suelen ser lo suficientemente grandes. A veces necesitas operar en números realmente grandes (módulos RSA, por ejemplo) que no encajan en esos registros. BC Math resuelve este problema actuando como una capa de abstracción: convierte números enormes en largas cadenas de texto. Cuando llega el momento de realizar alguna operación, BC Math rompe concienzudamente las largas cadenas de texto en pequeños trozos que la computadora puede manejar. Es mucho, mucho más lento que las operaciones nativas, pero puede manejar números de tamaño arbitrario.