Una biblioteca PHP simple de números romanos
Esta biblioteca incluye un par de filtros simples para convertir una string
con número romano en un int
que representa la entrada como decimal y int
decimal en una string
con número romano como resultado.
use Romans Filter RomanToInt ;
$ filter = new RomanToInt ();
$ result = $ filter -> filter ( ' MCMXCIX ' ); // 1999
use Romans Filter IntToRoman ;
$ filter = new IntToRoman ();
$ result = $ filter -> filter ( 1999 ); // MCMXCIX
Este paquete utiliza Composer como repositorio predeterminado. Puede instalarlo agregando el nombre del paquete en la sección require
de composer.json
, apuntando a la última versión estable.
{
"require" : {
"wandersonwhcr/romans" : " ^1.0 "
}
}
Además, Romanos utiliza versiones semánticas. Las siguientes versiones de paquetes admiten estas versiones de PHP:
1.0.*
: PHP ^7.0
(Augusto)1.1.*
: PHP ^7.0
(Tiberio)1.2.*
: PHP >=7.4
(Calígula)1.3.*
: PHP >=7.4
(Claudio)1.4.*
: PHP >=7.4
(Nero)1.5.*
: PHP >=8.0
(Galba) Esta biblioteca se puede utilizar como dependencia para proyectos, facilitando las integraciones con bibliotecas o marcos. Si desea agregar más elementos a esta lista, abra una incidencia o cree una solicitud de extracción, agregando su proyecto en orden alfabético.
El paquete Romans
utiliza un enfoque Lexer-Parser y un autómata finito determinista (DFA) para convertir números romanos a int
, utilizando una biblioteca de tokens gramaticales.
use Romans Grammar Grammar ;
use Romans Lexer Lexer ;
use Romans Parser Parser ;
$ grammar = new Grammar ();
$ lexer = new Lexer ( $ grammar );
$ parser = new Parser ( $ grammar );
$ tokens = $ lexer -> tokenize ( ' MCMXCIX ' );
/*
$tokens = [
0 => 'M' // Grammar::T_M
1 => 'C', // Grammar::T_C
2 => 'M', // Grammar::T_M
3 => 'X', // Grammar::T_X
4 => 'C', // Grammar::T_C
5 => 'I', // Grammar::T_I
6 => 'X', // Grammar::T_X
];
*/
$ result = $ parser -> parse ( $ tokens ); // 1999
El filtro RomanToInt
usa Lexer para tokenizar la entrada y Parser para construir el número int
. Cuando se encuentran errores, Lexer o Parser lanzan excepciones para notificar el problema con un código específico.
use Romans Filter RomanToInt ;
use Romans Lexer Exception as LexerException ;
use Romans Parser Exception as ParserException ;
$ filter = new RomanToInt ();
try {
$ filter -> filter ( $ input );
} catch ( LexerException $ e ) {
// Unknown Token (LexerException::UNKNOWN_TOKEN)
} catch ( ParserException $ e ) {
// Invalid Token Type (Not String) (ParserException::INVALID_TOKEN_TYPE)
// Unknown Token (ParserException::UNKNOWN_TOKEN)
// Invalid Roman (ParserException::INVALID_ROMAN)
}
Puedes usar esta estructura para validar números romanos, agregando un bloque try..catch para verificar si $input
es válido. Además, puede validar si un int
se puede filtrar a Roman usando un filtro IntToRoman
.
use Romans Filter IntToRoman ;
use Romans Filter Exception as FilterException ;
$ filter = new IntToRoman ();
try {
$ filter -> filter ( $ input );
} catch ( FilterException $ e ) {
// Invalid Integer (< 0) (FilterException::INVALID_INTEGER)
}
El valor cero se representa como string
"N"
, la inicial de nulla o nihil , la palabra latina para "nada" (ver referencias).
use Romans Filter RomanToInt ;
use Romans Filter IntToRoman ;
$ filter = new RomanToInt ();
$ result = $ filter -> filter ( ' N ' ); // 0 (Zero)
$ filter = new IntToRoman ();
$ result = $ filter -> filter ( 0 ); // N
Este paquete utiliza la interfaz de almacenamiento en caché PSR-6 para mejorar la ejecución, principalmente en bucles (como while
o foreach
) utilizando bibliotecas de caché. Se puede utilizar cualquier implementación de PSR-6 y sugerimos el paquete Symfony Cache.
use Romans Filter IntToRoman ;
use Romans Filter RomanToInt ;
use Symfony Component Cache Adapter ArrayAdapter ;
$ cache = new ArrayAdapter ();
$ filter = new RomanToInt ();
$ filter -> setCache ( $ cache );
$ result = $ filter -> filter ( ' MCMXCIX ' ); // 1999
$ result = $ filter -> filter ( ' MCMXCIX ' ); // 1999 (from cache)
$ filter = new IntToRoman ();
$ filter -> setCache ( $ cache );
$ result = $ filter -> filter ( 1999 ); // MCMXCIX
$ result = $ filter -> filter ( 1999 ); // MCMXCIX (from cache)
Puede utilizar Docker Compose para crear una imagen y ejecutar un contenedor para desarrollar y probar este paquete.
docker-compose build
docker-compose run --rm romans composer install
docker-compose run --rm romans composer test
Esta sección describe las técnicas utilizadas por este paquete para convertir números romanos a int
y viceversa.
Se eligió un enfoque Lexer-Parser porque la validación y lectura de números romanos están más simplificadas: Lexer es responsable de leer y transformar la entrada en tokens, validando el contenido a nivel de caracteres; y el Parser se encarga de transformar los tokens en números, validar el contenido a nivel de posición y convertirlo a int
a través de un DFA.
Wikipedia dice que "el análisis léxico es el proceso de convertir una secuencia de caracteres en una secuencia de tokens", que "es una estructura que representa un lexema que indica explícitamente su categorización con el fin de analizarlo". Incluso, Wikipedia dice que "el análisis sintáctico o de sintaxis es el proceso de analizar símbolos conforme a las reglas de una gramática formal".
Esta estructura facilita el desarrollo de una estructura encargada de leer una string
de entrada, convirtiéndola en otra estructura según el conjunto de caracteres específico y su posición dentro de la entrada.
Se desarrolló un DFA para comprobar si una string
con número romano es válida. Se eligió esta técnica porque otras implementaciones simplemente convierten la entrada sin verificar reglas, como cuatro caracteres secuencialmente.
La definición actual de autómata se declara a continuación.
M = (Q, Σ, δ, q0, F)
Q = { a, b, c, d, e, f, g, y, z }
Σ = { I, V, X, L, C, D, M, N }
q0 = g
F = { z }
z -> ε
y -> $z
a -> y | Iy | IIy | IIIy
b -> a | IVy | Va | IXy
c -> b | Xb | XXb | XXXb
d -> c | XLb | Lc | XCb
e -> d | Cd | CCd | CCCd
f -> e | CDd | De | CMd
g -> f | Ny | Mg
Este paquete es de código abierto y está disponible bajo la licencia MIT descrita en LICENCIA.