print_r imprimir error convert conversion consola cast array php regex arrays preg-match explode

imprimir - php cast array to string



ParĂ¡metros de la consola de cadena de PHP a la matriz (7)

Me gustaría saber cómo podría transformar la cadena dada en el arreglo especificado:

Cuerda

all ("hi there /(option/)", (this, that), other) another

Resultado buscado (Array)

[0] => all, [1] => Array( [0] => "hi there /(option/)", [1] => Array( [0] => this, [1] => that ), [2] => other ), [2] => another

Esto se usa para un tipo de consola que estoy haciendo en PHP. Intenté usar preg_match_all , pero no sé cómo podría encontrar paréntesis entre paréntesis para "hacer matrices dentro de matrices".

EDITAR

Todos los demás caracteres que no se especifican en el ejemplo deben tratarse como una String .

Editar 2

Olvidé mencionar que todos los parámetros que están fuera de los paréntesis deben ser detectados por el carácter de space .


El resumen de 10,000 pies

Debe hacer esto con un pequeño analizador personalizado: el código toma información de este formulario y lo transforma en el formulario que desea.

En la práctica, me parece útil agrupar problemas de análisis como este en una de las tres categorías según su complejidad:

  1. Trivial: problemas que se pueden resolver con unos pocos bucles y expresiones regulares humanas. Esta categoría es seductora: incluso si está un poco inseguro de si el problema puede resolverse de esta manera, una buena regla general es decidir que no puede.
  2. Fácil: los problemas que requieren la construcción de un pequeño analizador por ti mismo, pero son lo suficientemente simples como para que no tenga sentido sacar las armas grandes. Si necesita escribir más de ~ 100 líneas de código, considere escalar a la siguiente categoría.
  3. Involucrado: problemas para los que tiene sentido ir formal y utilizar un generador de analizador comprobado ya existente.

Clasifico este problema particular como perteneciente a la segunda categoría, lo que significa que puedes enfocarlo así:

Escribiendo un pequeño analizador

Definiendo la gramática

Para hacer esto, primero debe definir, al menos informalmente, con algunas notas rápidas, la gramática que desea analizar. Tenga en cuenta que la mayoría de las gramáticas se definen recursivamente en algún momento. Así que digamos que nuestra gramática es:

  • La entrada es una secuencia.
  • Una secuencia es una serie de cero o más tokens.
  • Un token es una palabra , una cadena o una matriz
  • Los tokens están separados por uno o más caracteres de espacio en blanco
  • Una palabra es una secuencia de caracteres alfabéticos (az)
  • Una cadena es una secuencia arbitraria de caracteres entre comillas dobles
  • Una matriz es una serie de una o más fichas separadas por comas.

Puede ver que tenemos recursión en un lugar: una secuencia puede contener matrices, y una matriz también se define en términos de una secuencia (por lo que puede contener más matrices, etc.).

Tratar el asunto de manera informal como anteriormente es más fácil como introducción, pero razonar sobre las gramáticas es más fácil si lo haces formally .

Construyendo un lexer

Con la gramática en mano, debe dividir la entrada en tokens para que pueda procesarse. El componente que toma la entrada del usuario y la convierte en piezas individuales definidas por la gramática se denomina lexer . Lexers son tontos; solo se preocupan por la "apariencia externa" de la entrada y no intentan verificar que realmente tenga sentido.

Aquí hay un simple lexer que escribí para analizar la gramática anterior (no use esto para nada importante; puede contener errores):

$input = ''all ("hi there", (this, that) , other) another''; $tokens = array(); $input = trim($input); while($input) { switch (substr($input, 0, 1)) { case ''"'': if (!preg_match(''/^"([^"]*)"(.*)$/'', $input, $matches)) { die; // TODO: error: unterminated string } $tokens[] = array(''string'', $matches[1]); $input = $matches[2]; break; case ''('': $tokens[] = array(''open'', null); $input = substr($input, 1); break; case '')'': $tokens[] = array(''close'', null); $input = substr($input, 1); break; case '','': $tokens[] = array(''comma'', null); $input = substr($input, 1); break; default: list($word, $input) = array_pad( preg_split(''/(?=[^a-zA-Z])/'', $input, 2), 2, null); $tokens[] = array(''word'', $word); break; } $input = trim($input); } print_r($tokens);

Construyendo un analizador

Una vez hecho esto, el siguiente paso es crear un parser : un componente que inspecciona la entrada lexed y la convierte al formato deseado. Un analizador es inteligente; en el proceso de convertir la entrada, también se asegura de que la entrada esté bien formada por las reglas de la gramática.

Los analizadores se implementan comúnmente como máquinas de estado (también conocidas como máquinas de estado finito o autómatas finitos) y funcionan de la siguiente manera:

  • El analizador tiene un estado ; este suele ser un número en un rango apropiado, pero cada estado también se describe con un nombre más amigable para los humanos.
  • Hay un bucle que lee los tokens lexed leídos de uno en uno. Según el estado actual y el valor del token, el analizador puede decidir realizar una o más de las siguientes acciones:
    1. Tomar alguna acción que afecte su salida.
    2. cambiar su estado a otro valor
    3. Decide que la entrada está mal formada y produce un error.

Gener Los generadores de analizador son programas cuya entrada es una gramática formal y cuya salida es un lexer y un analizador al que puede "simplemente agregar agua": simplemente extienda el código para realizar "realizar alguna acción" según el tipo de token; Todo lo demás ya está cuidado. Una búsqueda rápida sobre este tema le da a PHP Lexer y Parser Generator?


No hay duda de que debería escribir el analizador si está creando un árbol de sintaxis. Pero si solo necesita analizar este ejemplo, la regex entrada puede ser una herramienta:

<?php $str = ''all, ("hi there", (these, that) , other), another''; $str = preg_replace(''//, /'', '','', $str); //get rid off extra spaces /* * get rid off undefined constants with surrounding them with quotes */ $str = preg_replace(''/(/w+),/'', ''/'$1/','', $str); $str = preg_replace(''/(/w+)/)/'', ''/'$1/')'', $str); $str = preg_replace(''/,(/w+)/'', '',/'$1/''', $str); $str = str_replace(''('', ''array('', $str); $str = ''array(''.$str.'');''; echo ''<pre>''; eval(''$res = ''.$str); //eval is evil. print_r($res); //print the result

Demo

Nota: Si la entrada está mal formada, la expresión regular fallará definitivamente. Estoy escribiendo esta solución en caso de que necesite un script rápido. Escribir lexer y parser es un trabajo que requiere mucho tiempo, que requerirá mucha investigación.


Pondré el algoritmo o pseudo código para implementar esto. Esperemos que puedas encontrar la manera de implementarlo en PHP:

function Parser([receives] input:string) returns Array define Array returnValue; for each integer i from 0 to length of input string do charachter = ith character from input string. if character is ''('' returnValue.Add(Parser(substring of input after i)); // recursive call else if character is ''"'' returnValue.Add(substring of input from i to the next ''"'') else if character is whitespace continue else returnValue.Add(substring of input from i to the next space or end of input) increment i to the index actually consumed return returnValue


Por lo que sé, el problema de los paréntesis es una clase de lenguaje 2 de Chomsky, mientras que las expresiones regulares son equivalentes a la clase 3 de lenguaje de Chomsky, por lo que no debería haber una expresión regular, lo que resuelve este problema.

Pero leí algo no hace mucho:

Este patrón de PCRE resuelve el problema de paréntesis (supongamos que la opción PCRE_EXTENDED está configurada para que el espacio en blanco se ignore): /( ( (?>[^()]+) | (?R) )* /)

Con delimitadores y sin espacios: //(((?>[^()]+)|(?R))*/)/ .

Esto es de los patrones recursivos (PCRE) - manual de PHP .

¡Hay un ejemplo en ese manual, que resuelve casi el mismo problema que usted especificó! Usted u otros pueden encontrarlo y continuar con esta idea.

Creo que la mejor solución es escribir un patrón recursivo enfermo con preg_match_all . Lamentablemente no estoy en el poder de hacer tal locura!


Primero, quiero agradecer a todos los que me ayudaron en esto.

Desafortunadamente, no puedo aceptar respuestas múltiples porque, si pudiera, les daría a todos porque todas las respuestas son correctas para diferentes tipos de este problema.

En mi caso, solo necesitaba algo simple y sucio y, siguiendo las respuestas de @palindrom y @PLB, tengo lo siguiente trabajando para mí:

$str=transformEnd(transformStart($string)); $str = preg_replace(''/([^///])/(/'', ''$1array('', $str); $str = ''array(''.$str.'');''; eval(''$res = ''.$str); print_r($res); //print the result function transformStart($str){ $match=preg_match(''/(^/(|[^///]/()/'', $str, $positions, PREG_OFFSET_CAPTURE); if (count($positions[0])) $first=($positions[0][1]+1); if ($first>1){ $start=substr($str, 0,$first); preg_match_all("/(?:(?:/"(?://///"|[^/"])+/")|(?:''(?:///'|[^''])+'')|(?:(?:[^/s^/,^/"^/']+)))/is",$start,$results); if (count($results[0])){ $start=implode(",", $results[0]).","; } else { $start=""; } $temp=substr($str, $first); $str=$start.$temp; } return $str; } function transformEnd($str){ $match=preg_match(''/(^/)|[^///]/))/'', $str, $positions, PREG_OFFSET_CAPTURE); if (($total=count($positions)) && count($positions[$total-1])) $last=($positions[$total-1][1]+1); if ($last==null) $last=-1; if ($last<strlen($str)-1){ $end=substr($str,$last+1); preg_match_all("/(?:(?:/"(?://///"|[^/"])+/")|(?:''(?:///'|[^''])+'')|(?:(?:[^/s^/,^/"^/']+)))/is",$end,$results); if (count($results[0])){ $end=",".implode(",", $results[0]); } else { $end=""; } $temp=substr($str, 0,$last+1); $str=$temp.$end; } if ($last==-1){ $str=substr($str, 1); } return $str; }

Otras respuestas también son útiles para quienes buscan una mejor manera de hacerlo.

Una vez más, gracias a todos = D.


Quiero saber si esto funciona:

  1. reemplazar ( con Array(
  2. Use expresiones regulares para poner una coma después de las palabras o paréntesis sin comas

    preg_replace( ''/[^,]/s+/'', '','', $string )

  3. eval( "/$result = Array( $string )" )


Si los valores de cadena son fijos, se puede hacer de esta manera.

$ar = explode(''("'', $st); $ar[1] = explode(''",'', $ar[1]); $ar[1][1] = explode('','', $ar[1][1]); $ar[1][2] = explode('')'',$ar[1][1][2]); unset($ar[1][1][2]); $ar[2] =$ar[1][2][1]; unset($ar[1][2][1]);