Hola a todos, este post es para que aquellos más avanzados en php me dejen sus opiniones acerca del parseo de textos. Realmente el objetivo es simplemente educativo, es decir quiero escribir un supuesto lenguaje y un intérprete en php.
El caso es que he estado haciendo pruebas con las funciones de cadenas de php, como sean explode(), por ejemplo, y no me valen, pues no son seguras, ya que si les pasamos un valor de tipo string que contenga "caracteres reservados" no controlas el corte y puede producir resutados inesperados.
Luego he estado haciendo pruebas con lectura secuencial (no se si lo llamo correctamente) en la cual, se va leyendo linea por linea y caracter por caracter usando varios bucles anidados. Este método es más seguro, ya que puedo controlar el parseo e incluso detectar los errores en su linea y caracter. Pero noto que el rendimiento es bajo, y solo lo he probado leyendo una instrucción sencilla.
Código PHP:
foreach($fcontents AS $line=>$lvalue)
{
//Obtener longitud de la cadena
$lineLenght = strlen(trim($lvalue));
$lvalue = trim($lvalue);
//Puntero de la posición de la última acción en la lectura de la línea.
$lPos = 0;
//Puntero de la posición actual de lectura en la línea.
$p = 0;
//Contiene el nombre del atributo
$tmpAtbName = "";
//Contiene el valor del atributo
$tmpAtbValue = "";
//Array multidimensional que contiene la lectura de toda la secuencia
//que luego será utilizada en el script para realizar las
$lineParsed = array();
//Ignoramos las líneas vacías
if($lineLenght > 1)
{
#BUCLE GENERAL DE LECTURA DE LINEA#################################
//Este bucle lee toda la línea y va dividiendola en porciones según su cometido y valor.
while($p < $lineLenght)
{
#OBTENER MODO DE FORMULARIO###############################
//Obtener el modo de formulario (Crear, Modificar, Eliminar)
//Onbtener carácter a caracter el nombre de tipo
if(ereg("[A-Za-z0-9\-_]", $lvalue[$p]))
{
$tmpAtbName .= $lvalue[$p];
$p++;
}
else
//Caracter distinto de alfanumérico más "-" y "_"
{
//Comprobar que tipo de caracter es
while($p < $lineLenght)
{
//Ignoramos los espacios en blanco
if(ereg("[ ]", $lvalue[$p]))
{
$p++;
}
//Cualquier caracter distinto de "(" produce un error fatal
elseif(ereg("[^\(]", $lvalue[$p]))
{
$this->trownFatalError("Error de lectura en el código: Nombre de tipo no válido linea: ".($line+1)." caracter: ".$p);
break 3;
}
//LLegados aquí, el caracter obtenido es "(" que indica el fin del nombre
//del tipo de formulario e indica el inicio de la especificación de atributos.
else
{
//Almacenamos el tipo de formulario
$lineParsed['formType'] = $tmpAtbName;
$p++;
break;
}
}
#OBTENEMOS LOS ATRIBUTOS DEL TIPO DE FORMULARIO###########
while($p < $lineLenght)
{
//Ignoramos todos los espacios en blanco en el principio
if(ereg("[ ]", $lvalue[$p]))
{
$p++;
}
//Buscamos la aparición de un primer caracter válido
elseif(ereg("[A-Za-z0-9\-_]", $lvalue[$p]))
{
//Iniciamos lectura del nombre del atributo
while($p < $lineLenght)
{
//Almacenamos los caracteres válidos
if(ereg("[A-Za-z0-9\-_]", $lvalue[$p]))
{
$tmpAtbName .= $lvalue[$p];
$p++;
}
else
{
//Comprobamos los caracteres no válidos
while($p < $lineLenght)
{
//Ignoramos los espacios en blanco
if(ereg("[ ]", $lvalue[$p]))
{
$p++;
}
//Cualquier caracter que no sea ":" produce un error fatal
elseif(ereg("[^:]", $lvalue[$p]))
{
$this->trownFatalError("Error de lectura en el código: Nombre de atributo no válido linea: ".($line+1)." caracter: ".$p);
break 5;
}
//Llegados a este punto hemos llegado al final del nombre de atributo
else
{
$p++;
}
}
}
}
}
//En este punto de lectura no puede haber ningún caracter distinto de
//A-Z,a-z,0-9, "-" o "_". Error fatal
else
{
$this->trownFatalError("Error de lectura en el código: Atributos de tipo mal formulados linea:".($line+1)." caracter: ".$p);
break 3;
}
Luego he probado las expresiones regulares. Tengo más control, pero aún así siguen siendo poco seguras porque no consigo estraer los nombres y valores de manera segura y óptima.
Código PHP:
$string = 'create(atributo1 : "\"mi atributo1\""; atributo2: "proba atribut 2"; atreatribut3: "mes valor3"; atributo4: "att4";)';
//Conte el nom de la funció
preg_match("/[A-Za-z0-9\-_]+[ ]?[\(]/", $string, $res3);
//Conte els atributs de la funció
$res4 = preg_split("/[A-Za-z0-9\-_]+[ ]?[\(]/", $string);
$fatributos = substr($res4[1], 0, -1);
//Conte el valor dels atributs
$res = preg_split("/[\s]?[a-zA-Z0-9]+[\s]?[:]/", $fatributos);
//Conte el nom dels atributs
preg_match_all("/[\s]?[a-zA-Z0-9]+[\s]?[:]/", $fatributos, $res2);
echo "Función: ".substr($res3[0], 0, -1);
echo "<br /><br />";
for($i=0; $i < count($res2[0]); $i++)
{
echo $res2[0][$i].$res[($i+1)]."<br />";
}
¿Cuáles con sus opiniones?¿Como puedo mejorar las expresiones regulares para que sean más fiables?