Panfix a infijo entre paréntesis

16

Quylthulg es un lenguaje de Chris Pressey que intenta resolver el problema de la notación infija usando lo que llama panfix :

Al igual que Postfix, Panfix no requiere el despliegue de artilugios arcanos como paréntesis para anular una precedencia de operador predeterminada. Al mismo tiempo, panfix permite que los términos se especifiquen en el mismo orden y forma que infix, una notación indudablemente natural e intuitiva para aquellos que se han acostumbrado a ello.


¿Cómo se obtiene la conveniencia de la notación de infijo junto con la inequívoca de prefijo o postfix? ¡Usa los tres, por supuesto!

=y=+*3*x*+1+=

Más formalmente, seamos +un operador, ay bseamos expresiones. Entonces (a+b)es una expresión infija válida (entre paréntesis), la representación panfix de esa expresión es +a+b+, donde la yuxtaposición representa la concatenación.

Su objetivo es tomar una cadena de panfix y convertirla en un infijo completamente entre paréntesis:

(y=((3*x)+1))

Para simplificar, haremos los siguientes cambios:

  • Los operadores solo pueden constar de dos caracteres únicos (puede elegir cualquiera, pero aquí usaré *y +).
  • Solo hay un literal, que consiste en otro carácter distinto (puede elegir cualquiera, pero aquí lo usaré _).
  • La entrada será una expresión panfix bien formada.

Por complejidad , haremos el siguiente cambio:

  • Los operadores pueden constar de cualquier número positivo de caracteres, no solo uno.

Esto hace que el desafío sea más complicado porque no se puede determinar necesariamente cómo se divide una subcadena determinada de caracteres del operador sin mirar el resto de la cadena.

Aquí hay una implementación de referencia para el desafío, cortesía de @ user202729.

Casos de prueba

format: input -> output
+*+_*+_*+++_+*+_*+_*+++ -> ((_*+_)+(_+(_*+_)))
**++*+***++_+_++_+*++*+***_*++*+*****_**_*_*** -> ((((_+_)+_)*++*+***_)*(_*(_*_)))
***_**_***_* -> ((_**_)*_)
+_+_+ -> (_+_)
*+*+++**+***+++++_*+*+++**+***+++++_*+*+++**+***+++++ -> (_*+*+++**+***+++++_)
*++++*+*_*_*+*+++****+_++****+_++****++*+*+++_*+++ -> (((_*_)+*+(_++****+_))*+++_)
+**+_*+_*+*_*+*_*+*_+*_+**+ -> (((_*+_)*_)+(_*(_+*_)))
+**+++++_+++++_+++++*_*+*+_++++++_+++++_+++++++* -> (((_+++++_)*_)+*(_+(_+++++_)))
+*+*+_+*+_+*+*_*+*_*+*+_+*+_+*+*+ -> (((_+*+_)*_)+(_*(_+*+_)))
**_**_**_*_****_* -> ((_*(_*(_*_)))*_)

Utilicé este programa para generar cadenas de infijo para este desafío (la conversión a panfix fue trivial, pero la inversión no lo es).

Fruta Esolanging
fuente
2
Lo inverso
Conor O'Brien
2
Relacionado
HyperNeutrino
66
Caso de prueba sugerida: **_**_**_*_****_*. Todas las respuestas que he probado han fallado en esta.
Nitrodon
1
¿Puedo tener espacios adicionales en mi salida, por ejemplo (_ + _)?
Ton Hospel
2
@TonHospel Claro.
Esolanging Fruit

Respuestas:

6

Prólogo (SWI) , 194 163 bytes

¡Ahorré la friolera de 31 bytes usando este consejo de 0 ' !

[C|T]/O/R:-C\=x,(T/P/R,concat(C,P,O);O=C,R=T).
[x|R]-x-R.
L-X-R:-L/O/A,A-Y-B,B/O/C,C-Z-D,D/O/R,atomics_to_string(['(',Y,O,Z,')'],X).
X^P:-string_chars(X,L),L-P-[].

El operador ^toma para su argumento izquierdo una cadena que contiene una expresión panfix y establece su argumento derecho en una cadena que contiene la expresión infija entre paréntesis correspondiente. Se utiliza xcomo literal en lugar de _.

Pruébalo en línea!

Explicación

Como Prolog es un lenguaje declarativo, solo tenemos que describir la relación entre un panfix y una expresión entre paréntesis.

La explicación utiliza esta versión un poco no golfista:

oper([C|T],O,R) :- C\=x, oper(T,P,R), concat(C,P,O).
oper([C|T],C,T).

expr([x|R],x,R).
expr(L,X,R) :- oper(L,O,A), expr(A,Y,B), oper(B,O,C), expr(C,Z,D), oper(D,O,R),
               atomics_to_string(['(',Y,O,Z,')'],X).

parenthesize(X,P) :- string_chars(X,L), expr(L,P,[]).

Nuestra producción principal es parenthesize, que toma una expresión panfix Xcomo una cadena y envía la expresión infija entre paréntesis correspondiente Pcomo una cadena. Se utiliza string_charspara convertir la cadena de entrada en una lista de caracteres y luego simplemente se la pasa expr.

exprtoma una lista de caracteres L, analiza la primera expresión panfix que encuentra Ly envía el equivalente entre paréntesis Xy el resto de la lista de caracteres R. Hay dos tipos posibles de expresiones:

  • Si el primer carácter de Les x, entonces la expresión es xy el resto es todo después de x.
  • De lo contrario, analice un operador O(ver más operabajo); analizar una expresión Y; analizar de Onuevo; analizar otra expresión Z; y analizar Opor tercera vez. El resto es todo después de la tercera instancia de O. La expresión es el resultado de la unión Y, Oy Z, rodeado de paréntesis, en una cadena.

opertoma una lista de personajes, donde está el primer personaje Cy el resto T; analiza un operador (es decir, una serie de uno o más caracteres de operador) y envía el operador Oy el resto de la lista de caracteres R. Para formar un operador, el personaje Cdebe ser algo distinto de x; también

  • un operador Pdebe ser analizable desde T, con el resto R; en este caso, Oes la concatenación de Cy P; o,
  • Oes el personaje único C; En este caso, Res justo T.

Un ejemplo trabajado

Tomemos la entrada +*+x+x++*x+*como ejemplo.

  • Queremos analizar una expresión de +*+x+x++*x+*. Esto no comienza con x, por lo que analizamos un operador desde el principio.
  • operanalizará un operador lo más grande posible, así que lo intentamos +*+.
    • A continuación analizamos una expresión de x+x++*x+*. Esto tiene que ser x.
    • Ahora intentamos analizar el mismo operador +*+, desde +x++*x+*. Sin embargo, esto falla .
  • Entonces retrocedemos e intentamos analizar el operador en su +*lugar.
    • Analizamos una expresión de +x+x++*x+*. Esto no comienza con x, por lo que debemos analizar un operador.
    • La única posibilidad es +.
    • Ahora analiza una subexpresión de x+x++*x+*. Esto tiene que ser x.
    • Ahora analiza de +nuevo desde +x++*x+*.
    • Ahora analiza otra subexpresión de x++*x+*. Esto tiene que ser x.
    • Finalmente, analiza +nuevamente desde ++*x+*.
    • La expresión se ha analizado correctamente. Devolvemos la cuerda (x+x).
  • De vuelta al nivel de recursión anterior, analizamos +*nuevamente el operador desde +*x+*.
  • Ahora analiza otra subexpresión de x+*. Esto tiene que ser x.
  • Finalmente, analiza +*nuevamente desde +*.
  • La expresión se ha analizado correctamente. Devolvemos la cuerda ((x+x)+*x).

Como no quedan más caracteres, hemos traducido con éxito la expresión.

DLosc
fuente
4

Perl, 78 60 58 57 50 bytes

Incluye +1parap

Usos 1para +y 2para *(o, de hecho, cualquier dígito funciona para cualquier operador)

perl -pe 's/\b((\d+)((?1)|_)\2((?3))\2)\b/($3 $2 $4)/&&redo' <<< 22_22_22_2_2222_2

Para una prueba conveniente en comparación con los ejemplos dados, puede usar esto, que realiza las traducciones y la eliminación de espacio por usted:

perl -pe 'y/+*/12/;s/\b((\d+)((?1)|_)\2((?3))\2)\b/($3 $2 $4)/&&redo;y/ //d;y/12/+*/' <<< "**_**_**_*_****_*"
Ton Hospel
fuente
3

Limpio , 200 192 189 bytes

import StdEnv,Text
f"_"=["_"]
f l=["("+a+p+b+")"\\p<-[l%(0,i)\\i<-[0..indexOf"_"l]|endsWith(l%(0,i))l],t<-[tl(init(split p l))],n<-indexList t,a<-f(join p(take n t))&b<-f(join p(drop n t))]

Pruébalo en línea!

Define la función f, tomar Stringy devolver un singleton[String] con el resultado dentro.

Algunas cosas ordenadas:

  • No usa expresiones regulares
  • Funciona con cualquier personaje para operadores excepto_
Οurous
fuente
3

Retina 0.8.2 , 138 bytes

.+
($&)
+`\((\d+)(_|((?<i>(?<i>\d+))|_(?<-i>\k<i>)+)+(?(i)(?!)))\1(_|((?<i>(?<i>\d+))|_(?<-i>\k<i>)+)+(?(i)(?!)))\1\)
(($2)$1($4))
\(_\)
_

Pruébalo en línea! El enlace incluye los casos de prueba más rápidos. Explicación: El motor de expresiones regulares utiliza el retroceso para dividir la cadena en tokens que luego se empujan o se sacan del igrupo de equilibrio. Siempre se ejecuta al menos un operador al inicio antes de la primera variable. Después de una variable, aparece al menos un operador, momento en el cual un operador empujado ejecuta u otra variable es legal. Los operadores son empujados al grupo por duplicado para que puedan aparecer correctamente. Ejemplo:

Input           Stack
Push *          * *
Push *++*+***   * * *++*+*** *++*+***
Push +          * * *++*+*** *++*+*** + +
Push +          * * *++*+*** *++*+*** + + + +
Variable _
Pop +           * * *++*+*** *++*+*** + + +
Variable _
Pop +           * * *++*+*** *++*+*** + +
Pop +           * * *++*+*** *++*+*** +
Variable _
Pop +           * * *++*+*** *++*+***
Pop *++*+***    * * *++*+***
Variable _
Pop *++*+***    * *
Pop *           *
Push *          * * *
Variable _
Pop *           * *
Push *          * * * *
Variable _
Pop *           * * *
Variable _
Pop *           * *
Pop *           *
Pop *

Desafortunadamente, esto no nos ayuda a capturar los resultados para agruparlos, por lo que el operador externo se compara manualmente. Los corchetes se agregan de afuera hacia adentro, por lo que la primera etapa envuelve toda la expresión entre corchetes y la última etapa los elimina ahora que se han propagado a las variables.

Neil
fuente
1
Esto también falla por **_**_**_*_****_*.
user202729
@ user202729 ¿Trabajas ahora?
Neil
@Neil Está funcionando ahora, sí.
Horrible
1

Haskell , 167 166 bytes

head.e
e('_':r)=["_",r]
e(x:r)=[x]%r
e _=[]
o%t@(c:r)|[x,u]<-e t,n<-length o,[y,v]<-e$drop n u,all((==o).take n)[u,v]=['(':x++o++y++")",drop n v]|p<-o++[c]=p%r
o%_=[]

Pruébalo en línea! Ejemplo de uso: head.e "**_**_**_*_****_*"rendimientos ((_*(_*(_*_)))*_). Todos los caracteres excepto _se interpretan como operadores, en _sí denota un identificador.

Laikoni
fuente
0

Python 3, 226 bytes

from re import*
P=r'([*+]+)'+r'(\(.+?\)|_)\1'*2;R=lambda i,J=lambda i,o:i[:o]+sub(P,lambda o:'('+o[2]+o[1]+o[3]+')',i[o:],1),s=search:s(P,i)and R([J(i,o)for o in range(len(i))if s(P,J(i,o))or J(i,o)[0]+J(i,o)[-1]=='()'][0])or i

Define una función anónima llamada R.

Pruébalo en línea!

R. Kap
fuente
Tenga en cuenta que puede usar cualquier otro carácter que no sea _*+; esos fueron justo lo que se utilizó en el ejemplo. Es posible que pueda usar esto para golf sus expresiones regulares (por ejemplo, usando en \dlugar de [*+]).
Esolanging Fruit