Comunidad PHPeros

Otros => Los Retos PHPeros => Mensaje iniciado por: good en 13 de Agosto de 2011, 18:17:00 pm

Título: [Reto] Parser
Publicado por: good en 13 de Agosto de 2011, 18:17:00 pm
Hola
La idea es crear un script que parsee un string

la idea es crear como un pequeño lenguaje de programación. Las normas son:

Siempre que el script detecte un comentario (una linea que empieza con el carácter #) no la imprime
Si el programa encuentra un texto en forma $abc (donde abc es una secuencia no vacía de letras mayúsculas [A-Z], minúsculas [a-z], dígitos [0-9] o el carácter _ (subrayado)), entonces sabremos que estamos hablando de una variable, siempre que empiece con el carácter $.
Cada vez que el programa encuentre una variable ésta se substituirá por el valor de la variable, que por defecto será "nil" (en este problema no se dan valores a las variables, simplemente tienen un valor fijo)

En cualquier otro caso, el programa no substituye la secuencia

EJEMPLO DE ENTRADA:
# hola soy un comentario $variable $$hola
EJEMPLo DE SALIDA:
NADA (no se imprime nada, una linea en blanc)

EJEMPLO DE ENTRADA:
    $soy_variable $$$ $y_yo_123
EJEMPLo DE SALIDA:
    nil $$$ nil

EJEMPLO DE ENTRADA:
    $$$ $ $$$ $ $asd $343_34-holamundohola
EJEMPLo DE SALIDA:
    $$$ $ $$$ $ nil nil-holamundohola



No se pueden usar expresiones regulares
la solución puede ser por ejemplo una función, o un código con una variable con el string, eso no importa

fuente: olimpiada informática española
Título: Re:[Reto] Parser
Publicado por: Farresito en 13 de Agosto de 2011, 18:25:48 pm
Hombre, lenguaje de programación está lejos lejos. Esto es sencillo de hacer con cualquier lenguaje. Si me animo, lo hago en C y a ver que tal queda.

Por cierto, la idea es buena :)
Título: Re:[Reto] Parser
Publicado por: good en 13 de Agosto de 2011, 18:33:07 pm
Hombre, lenguaje de programación está lejos lejos. Esto es sencillo de hacer con cualquier lenguaje. Si me animo, lo hago en C y a ver que tal queda.

Por cierto, la idea es buena :)

quizás php no sea el lenguaje más sencillo de usar para esto, yo recomiendo usar c++
Título: Re:[Reto] Parser
Publicado por: Farresito en 13 de Agosto de 2011, 18:41:18 pm
Me refiero a que dices que vamos a crear un pequeño lenguaje de programación, cuando esto no es más que un programa que lee un archivo y lo modifica ;)
Título: Re:[Reto] Parser
Publicado por: good en 13 de Agosto de 2011, 18:45:33 pm
simplemente pido un script o programa que lea un string y la parsee, no quiero que sea muy complicado, esa es la idea
Título: Re:[Reto] Parser
Publicado por: Farresito en 13 de Agosto de 2011, 18:49:53 pm
Por cierto, confío en que tengas la solución. Yo no voy a postear y haber hecho el trabajo que otro tenía que hacer hasta que haya alguna prueba.
Título: Re:[Reto] Parser
Publicado por: good en 13 de Agosto de 2011, 21:26:43 pm
tengo una solución de coste lineal en c++
Título: Re:[Reto] Parser
Publicado por: nmartin021 en 23 de Septiembre de 2011, 02:35:51 am
Mañana editare este mensaje con la solucion porque la tengo pensada, pero ahora no puedo decirla porque estoy en el mobil :P
Pero basicamente primero borro los comentarios, luego busco las variables caracter a caracter de un array hecho con explode('$')
Pd: espero que esto sea un reto de verdad y no alguien que necesita un script ;)
EDIT:
Dejo el código por la mitad, porque la verdad es que sin expresiones regulares se me hace imposible :S
EDIT 2:
Te dejo el código usando una expresiones regulares (una sóla vez) para dar alguna idea a los demás y que se animen a hacerlo sin expresiones regulares :D

<?php
/*** Parser ****/
function showVars($string){
return preg_replace('/\$([a-z0-9_]+)/si', 'nil', $string); //sustituir variables por 'nil'
}
$string = '
#############################
#comentarios $algo $nil
#### asdasd \#adasd asd
Hola $nombre, espero que te sientas comodo en nuestro nuevo lenguaje de programacion :D
Se llama $nombre
#esto es un comentario';
$string = trim($string); //que los espacios no causen problemas
$ex = explode("\r\n", $string); //obtenemos cada linea en un array
$ac = count($ex);
for($i=0;$i<$ac;$i++){ // recorrer el array para eliminar los comentarios
if(substr($ex[$i],0,1)=='#'){ unset($ex[$i]); }
} //ya tenemos el code sin comentarios
$s = implode('<br />', $ex); //ponemos los saltos de linea en si sitio
$s = showVars($s); //obtenemos variables
echo $s; //y mostramos el resultado
?>
Título: Re:[Reto] Parser
Publicado por: good en 30 de Septiembre de 2011, 14:29:01 pm
no es correcto, ten en cuenta que los comentarios no solo se declaran en el primer caracter, puede ser "         #   comentario"

además, creo haber dejado bien claro que no hay que usar expresiones regulares! XDD
Título: Re:[Reto] Parser
Publicado por: nmartin021 en 07 de Septiembre de 2012, 21:28:04 pm
Siento revivir esto, pero... tengo la solución: (hecho por mi desde cero)
<?

// $nil - Lenguaje creado con PHP

/*

  - Reglas:

 * $[algo] se reemplaza con "nil"

 * Sin expresiones regulares

 * Los comentarios empiezan con # y pueden estar al principio o al final (o en medio) de una línea

  - NOTA:

 * Hay un bug - no te acepta la variable si es el primer caracter del código...

*/

class Nil{

        private $code; // code to parse

        private $vars = array(); // code variables

        var $anv = false; // true para aceptar $123, false para no aceptarlo



        // definir codigo

        function __construct($code){

                if(!$code){ return false; }

                $this->code = $code;

        }

        

        // devolver codigo; al ser protected no se puede acceder públicamente

        function getCode(){ return $this->code; }

        

        // procesar otro codigo

        function setCode($code){ $this->code = $code; }

        

        // borrar comentarios

        function removeComments(){

                $e = explode("\n", $this->code);

                for($i=0,$c=count($e);$i<$c;$i++){

                        if($e[$i][0] == '#'){

                                unset($e[$i]);

                        }elseif(($s = strpos($e[$i], '#')) !== false){

                                $e[$i] = substr($e[$i], 0, $s);

                        }

                }

                $this->code = implode("\n", $e);

        }

        

        // reemplazar variables

        function parseVars(){

                if(strpos($this->code, '$') === false){ return; }

                $v = 0;

                while(($v = strpos($this->code, '$', $v + 1)) !== false){

                        $i = $v + 1;

                        if(!$this->anv && ctype_digit($this->code[$i])) continue;

                        while(ctype_alpha($this->code[$i]) || ctype_digit($this->code[$i]) || $this->code[$i] == '_') $i++;

                        $var = substr($this->code, $v, $i);

                        $this->code = substr($this->code, 0, $v).'nil'.substr($this->code, $i);

                }

        }

        

        // devolver resultado final

        function process(){

                $this->removeComments();

                $this->parseVars();

                return $this->code;

        }

}

echo '<pre>';

// variables normales

$nil = new Nil('Test de variables: $var'); // output: "Test de variables: $var"

echo $nil->process();



echo "\n\n\n";



echo "variables que empiezan por numeros - no permitidas:\n";

$nil->setCode('myVar: $123var'); // output: "myVar: $123var"

echo $nil->process();



echo "\n\n\n";



echo "variables que empiezan por numeros - permitidas:\n";

$nil->anv = true;

$nil->setCode('myVar: $123var'); // output: "myVar: nil"

echo $nil->process();



echo "\n\n\n";



echo "comentarios:\n";

$nil->setCode('#soy un comentario de una linea'); // output: ""

echo $nil->process();



echo "\n\n\n";



echo "comentarios en medio de la linea:\n";

$nil->setCode('hi bitches#comentario alone'); // output: "hi bitches"

echo $nil->process();



echo '</pre>';

?>
Título: Re:[Reto] Parser
Publicado por: Physlet en 06 de Noviembre de 2012, 17:25:47 pm
nmartin, un dato sobre POO. Los constructores no deben retornan valores. Si ese false que retorna tu constructor es sinónimo de "error", mejor arroja una Exception.
Título: Re:[Reto] Parser
Publicado por: Animus en 28 de Enero de 2013, 09:54:24 am
Es tan sencillo como utilizar ob_start, si me animo hago luego una Parser.
Título: Re:[Reto] Parser
Publicado por: ilovepixel en 28 de Enero de 2013, 20:33:12 pm
No sé si será la solución más optima pero llegué a esto en js:

var s1 = "  $ $$$   $Variable_3213-321         # hola soy un comentario $variable $$hola";
var s2 = "$soy_variable $$$ $y_yo_123";
var s3 = "$$$ $ $$$ $ $asd $343_34-holamundohola";

//Sin Regex
function nrTrace(str) {
var r="",
g=str.split("\n");
for(var i=0;i<g.length;i++) {
var l=g[i].split(" ");
for(var j=0;j<l.length;j++) {

if(l[j].length>0) {
if(l[j].indexOf("#")>=0) break;
else if(l[j].indexOf("$")>=0) {
var n = l[j].indexOf("$");
if(l[j].charAt(n+1)!="$" | "-" && l[j].length>1) {
var y = l[j].split("-");
for(var u=0;u<y.length;u++) {
if(y[u].charAt(0)=="$") r+="nil";
else r+="-"+y[u];
}
}else r+=l[j];
}
}
r+=" ";
}
}
return r;
}

//Con Regex
function trace(str) {
var r="",
g = str.split(/\n/g);
for(var i=0;i<g.length;i++) {
var l = g[i].split(/\s/g);
for(var j=0;j<l.length;j++) {
if(l[j].indexOf("#")>=0) break;
else {
var v = l[j].replace(/\$[^$][0-9_a-z]+/,"nil");
r+=v+" ";
}
}
}
return r;
}

console.log("Sin Regex");
console.log(nrTrace(s1));
console.log(nrTrace(s2));
console.log(nrTrace(s3));
console.log("---------");
console.log("Con Regex");
console.log(trace(s1));
console.log(trace(s2));
console.log(trace(s3));


Lo probé en node.js y me devuelve:
Código: [Seleccionar]
Sin Regex
  $ $$$   nil-321
nil $$$ nil
$$$ $ $$$ $ nil nil-holamundohola
---------
Con Regex
  $ $$$   nil-321
nil $$$ nil
$$$ $ $$$ $ nil nil-holamundohola
Título: Re:[Reto] Parser
Publicado por: Nasty35 en 26 de Febrero de 2013, 16:34:39 pm
Lo he hecho en Java:
package parser;

public class Parser {

public static void main(String[] args) {
System.out.println(analize("esto $mola #mazo"));
}

public static String analize(String text) {
String analized = "";
if(text.startsWith("#")) {
// Nada
} else {
for(String linea : text.split(" ")) {
if(linea.startsWith("$")) {
String a = "";
if(linea.contains("-")) {
a = "-".concat(linea.split("-")[1]);
}
if(linea.replace("$", "").isEmpty()) {
analized += linea;
} else {
analized += "nil";
}
analized += a.concat(" ");
} else if(!linea.startsWith("#")) {
analized += linea.concat(" ");
}
}
}
return analized;
}

}