Porque no podemos tener suficiente golf esotérico, ¿verdad?
/// - barras pronunciadas: es un lenguaje pequeño y divertido basado en la s///
función de reemplazo de expresiones regulares de la fama de Perl. Contiene solo dos caracteres especiales, barra /
diagonal y barra diagonal inversa \
. Puede encontrar un artículo completo en el wiki de esolangs , pero reproduciré una descripción del lenguaje a continuación, así como algunos ejemplos.
En resumen, funciona identificando /pattern/repl/rest
en el programa y haciendo la sustitución tantas veces como sea posible. Ningún carácter es especial excepto /
y \
: /
delimita patrones y reemplazos en el programa, mientras le \
permite insertar caracteres literales /
o \
caracteres en su código. Notablemente, estas no son expresiones regulares, solo sustituciones simples de cadenas.
Su desafío es producir un intérprete para el lenguaje ///, ya sea como un programa que lee STDIN o como una función que toma un argumento de cadena, en la menor cantidad de caracteres posible.
Puede usar cualquier idioma excepto /// en sí mismo. No puede usar ninguna biblioteca que interprete ///; sin embargo, puede usar expresiones regulares, bibliotecas de expresiones regulares o bibliotecas de coincidencia de cadenas.
Ejecución
Hay cuatro estados, impresión , patrón , reemplazo y sustitución . En todos los estados excepto la sustitución :
- Si el programa está vacío, la ejecución se detiene.
- De lo contrario, si el primer carácter es
\
, haga algo con el siguiente carácter (si está presente) y elimine ambos del programa. - De lo contrario, si el primer carácter es
/
, elimínelo y cambie al siguiente estado. - De lo contrario, haz algo con el primer personaje y quítalo del programa.
- Repetir.
Los estados se desplazan por la impresión , el patrón , el reemplazo y la sustitución en orden.
- En el modo de impresión , 'hacer algo' significa dar salida al personaje.
- En el modo de patrón , "hacer algo" significa agregar el carácter al patrón actual.
- En el modo de reemplazo , 'hacer algo' significa agregar el personaje al Reemplazo actual.
En el modo de sustitución , sigue un conjunto diferente de reglas. Sustituya repetidamente la primera aparición del Patrón actual con el Reemplazo actual en el programa, hasta que no sean posibles más sustituciones. En ese punto, borre el Patrón y Reemplazo y regrese al modo de impresión .
En el programa /foo/foobar/foo foo foo
, sucede lo siguiente:
/foo/foobar/foo foo foo
foo foo foo
foobar foo foo
foobarbar foo foo
foobarbarbar foo foo
...
Esto se repite para siempre y nunca sale del modo de sustitución . Del mismo modo, si el Patrón está vacío, la primera aparición de la cadena vacía, al comienzo del programa, siempre coincide, por lo que el modo de sustitución se repite para siempre, sin detenerse nunca.
Ejemplos
no
Salida: no
.
/ world! world!/Hello,/ world! world! world!
Salida: Hello, world!
.
/foo/Hello, world!//B\/\\R/foo/B/\R
Salida: Hello, world!
.
a/ab/bbaa/abb
Salida: a
. El programa no se detiene.
//
Salida: ninguna.
///
Salida: ninguna. El programa no se detiene.
/\\/good/\/
Salida: good
.
También hay una cita en la wiki que puedes probar.
fuente
/-/World//--/Hello//--W/--, w/---!
¿Qué no se podría amar? (Intente eliminar guiones desde el final)\
personaje escapa a cualquier personaje que lo siga, incluido/
, que luego se puede usar normalmente. Si bien esto no parece mucho, esto hace que /// Turing-complete .///
IDE que estoy haciendo!Respuestas:
APL (133)
Esta es una función que toma el
///
código como argumento correcto.Sin golfos, con explicación:
fuente
///
y//foo/
(es decir, bucles para siempre)?/
aún se quedaría en ese punto.J -
181190170 charEsto fue una pesadilla. Lo reescribí desde cero, dos veces, porque me seguía molestando. Esta es una función que toma un único argumento de cadena y lo envía a STDOUT.
Para explicarlo, lo dividiré en subexpresiones.
i
(abreviatura de iterar ) es un adverbio. Toma un argumento verbal a la izquierda y devuelve un verbo(f)i
, que cuando se aplica a un argumento, se aplicaf
repetidamente al argumento hasta que ocurra una de dos cosas: encuentra un punto fijo (y = f y
) o arroja un error. El comportamiento de punto fijo es inherente^:_
y::]
maneja los errores.parse
tokeniza la entrada en lo que yo llamo forma medio analizada , y luego la corta en el '/' sin escape. Vincula las barras diagonales que se escapan a sus personajes, pero no elimina las barras diagonales inversas, por lo que podemos revertirlo o terminarlo según lo que queramos.La mayor parte del trabajo interesante ocurre en
;:
. Este es un primitivo intérprete de máquina secuencial, que toma una descripción de la máquina ((0;(0,:~1 0,.2);'\';&<1 0)
) a la izquierda y algo para analizar a la derecha. Esto hace la tokenización. Notaré que esta máquina específica en realidad trata el primer carácter no especial, incluso si es un\
y debería unirse. Hago esto por varias razones: (1) la tabla de estado es más simple, por lo que puede jugarse más; (2) podemos simplemente agregar un personaje ficticio al frente para esquivar el problema; y (3) ese personaje ficticio se analiza a medias sin costo adicional, por lo que puedo usarlo para configurar la fase de corte, a continuación.También usamos
<;._1
para cortar el resultado tokenizado en no escapado/
(que es lo que elijo ser el primer personaje). Esto es útil para extraer la salida, el patrón y el reemplazo deout/patt/repl/rest
todo en un solo paso, pero desafortunadamente también corta el resto del programa, donde necesitamos/
que permanezcan intactos. Los vuelvo a unir duranteeval
, porque<;._1
dejarlos en paz termina costando mucho más.La bifurcación se
(eval [ print)
ejecutaprint
en el resultado deparse
sus efectos secundarios y luego se ejecutaeval
.print
es un verbo simple que abre el primer cuadro (el que sabemos con certeza es salida), termina de analizarlo y lo envía a STDOUT. Sin embargo, también aprovechamos la oportunidad para definir un verbo de utilidadp
.p
se define como>@{.@[
, por lo que toma su argumento izquierdo (actúa como la identidad si se le da un solo argumento), toma el primer elemento de ese (identidad cuando se le da un escalar) y lo desempaqueta (identidad si ya no se encuentra en un recuadro). Esto será muy útilsub
.eval
evalúa el resto del programa procesado. Si no tenemos un patrón completo o un reemplazo completo,eval
lo descarta y solo devuelve una lista vacía, que finaliza la evaluación al hacer un error;:
(desdeparse
) en la próxima iteración. De lo contrario,eval
analiza completamente el patrón y el reemplazo, corrige el resto de la fuente y luego pasa ambos asub
. Por explosión:sub
es donde ocurre una ronda (posiblemente infinita) de sustituciones. Debido a la forma en que configuramoseval
, la fuente es el argumento correcto, y el patrón y el reemplazo se agrupan a la izquierda. Dado que los argumentos están ordenados de esta manera y sabemos que el patrón y el reemplazo no cambian dentro de una ronda de sustituciones, podemos usar otra característica dei
—el hecho de que solo modifica el argumento derecho y sigue pasando en la misma izquierda— para delegar a J la necesidad de preocuparse por hacer un seguimiento del estado.Sin embargo, hay dos puntos de problemas. El primero es que los verbos J pueden tener como máximo dos argumentos, por lo que no tenemos una manera fácil de acceder a ninguno de los que están agrupados, como el patrón y el reemplazo, aquí. Mediante el uso inteligente de la
p
utilidad que definimos, este no es un gran problema. De hecho, podemos acceder al patrón en un carácter, simplemente usandop
, debido a su>@{.@[
definición: el Unbox del primer elemento del argumento izquierdo. Obtener el reemplazo es un truco, pero la forma más corta seríap&|.
, 2 caracteres más cortos que sacarlo manualmente.El segundo problema es que
i
sale en puntos fijos en lugar de hacer un bucle para siempre, y si el patrón y el reemplazo son iguales y haces una sustitución, eso parece un punto fijo para J. Manejamos esto ingresando un bucle infinito de negación de 1 sobre y si detectamos que son iguales, esta es la-i@=`p@.~:~/
porción que reemplazap&|.
.Este ciclo se repite debido al uso de
i
, hasta quesub
salga algo fuera de los errores. Hasta donde yo sé, esto solo puede suceder cuando nos quedamos sin personajes, o cuando desechamos un conjunto incompleto de patrones y reemplazos.Datos curiosos sobre este golf:
;:
es más corto que iterar manualmente a través de la cadena.0{
debería tener la posibilidad de error antes desub
entrar en un bucle infinito, por lo que debería funcionar bien si el patrón coincide con el reemplazo pero nunca aparece en el resto de la fuente. Sin embargo, esto puede o no ser un comportamiento no especificado, ya que no puedo encontrar una cita de ninguna manera en los documentos. Whoopsiei
, esos errores quedan atrapados también. Dependiendo de cuándo presione Ctrl + C, podría:sub
ciclo tratando de concatenar un número a una cadena, y luego continúe interpretando /// como si hubiera terminado de sustituir una cadena consigo mismo un número infinito de veces.sub
mitad y continúe interpretando una expresión /// semicubierta.Ejemplo de uso:
fuente
/\\/good/\/
caso de prueba; la depuración me dice que el problema es mi uso1!:2&4
, ya que jqt no tiene stdin / out. Investigaré. ¿Cuáles son tus9!:12''
y9!:14''
?9!:12''
tiene 6 años y9!:14''
es j701 / 2011-01-10 / 11: 25.Perl - 190
Lee el
///
programa desde stdin hasta EOF.fuente
m/^(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*)$/s
, es decir, salida de partido, patrón y reemplazo al mismo tiempo, haría un golf más corto? Yo no conozco a ningún Perl./a/\0/a
Pip ,
100102 bytesNunca había probado que Pip estuviera completo en Turing (aunque obviamente es así), y en lugar de seguir la ruta habitual de BF, pensé que /// sería interesante. Una vez que tuve la solución, pensé en jugarlo y publicarlo aquí.
101 bytes de código, +1 para
-r
bandera:Aquí está mi versión sin golf con abundantes comentarios:
Pruébalo en línea! (Tenga en cuenta que TIO no da ningún resultado cuando el programa no termina, y también tiene un límite de tiempo. Para ejemplos más grandes y bucles infinitos, se recomienda ejecutar Pip desde la línea de comandos).
fuente
pip + -r
, 101 bytesC ++: Visual C ++ 2013 = 423, g ++ 4.9.0 = 442
Esto nunca ganará, pero como he decidido que todos mis futuros proyectos de software se escribirán en este increíble lenguaje, necesitaba un intérprete para él y pensé que también podría compartir el que hice ...
La diferencia en la puntuación es que Visual C ++ no necesita la primera inclusión, pero g ++ sí. La puntuación supone que los finales de línea cuentan como 1.
fuente
if(!o[i]);
comoif(P
para guardar caracteres, o estoy malentendido cómo funciona #define?P
inmain
tiene un espacio después, por lo que puede guardar un personaje reemplazando esos espacios con punto y coma y eliminándolo#define
. Luego, si puede usar#define
s dentro de otros, puede guardar algo más reescribiendoN(x)
como en(92==P
lugar deo[i]==92
eO
igualmente.N(x)
comoP;else if(n<x)(P==92?
y el cambio de las llamadas aN
podría ahorrar unos pocos bytes en consecuencia.Python 2 (236), Python 3 (198?)
Llamado como
d(r"""/foo/Hello, world!//B\/\\R/foo/B/\R""")
. Las comillas triples solo son necesarias si el///
programa contiene nuevas líneas; de lo contrario, las comillas simples están bien.EDITAR: Este intérprete ahora imprime las cosas como se esperaba (anteriormente solo se imprimía al final, ver comentarios). Para Python 3, elimine la primera línea (pero no tengo Python 3 en mi instalación antigua, así que no puedo estar seguro de que no haya otro cambio).
fuente
/a/ab/bbaa/abb
./a/ab/bbaa/abb
quedará atascado en un bucle sin fin sin imprimir nada, porque la primera sustitución esa
=>ab
. El correctoa/ab/bbaa/abb
funciona como se anuncia.-u
para forzar que el búfer de salida no esté protegido.Cobra - 226
fuente
Ruby ,
119110 bytesTermina con excepción
Pruébalo en línea!
Termina limpiamente (116 bytes)
Pruébalo en línea!
fuente
Python 2/3 (211 bytes)
El siguiente código, basado en la respuesta de Bruno Le Floch , es compatible con Python 2 y Python 3.
Además, al ser iterativo en lugar de recursivo, no corre el riesgo de alcanzar la máxima profundidad de recursión de Python.
fuente
in(0,1,2)
ain 0,1,2
y[""]*2+[1]
a["","",1]
, lo que resulta en 211 bytes .Tocino ,
391387395 bytesDe las contribuciones en esta página solo conseguí que el programa Python funcionara. Los otros trabajan para algunas muestras ///, o no funcionan en absoluto. Por lo tanto, decidí agregar mi versión, que es una implementación en BASIC.
Competir en un concurso de CodeGolf con BASIC no es fácil, ya que BASIC usa palabras largas como declaraciones. La única abreviatura que se encuentra comúnmente en BASIC es el '?' signo, que significa IMPRIMIR.
Por lo tanto, el programa a continuación puede que nunca gane, pero al menos funciona con todos los códigos de demostración en esta página de Codegolf y en Wiki Wiki de Esolangs . Incluidas todas las versiones de las "99 botellas de cerveza".
fuente