Actualizador de archivos de idioma de Minecraft

11

En 1.13, los archivos de idioma de Minecraft se cambiaron de ser un formato simple de clave = valor de varias líneas a JSON .

Desafío

Escriba un programa que convierta del formato original y devuelva una cadena JSON. La entrada se puede tomar usando cualquier método de entrada estándar, la salida debe ser json de cualquier método de salida estándar

El formato original contiene líneas con pares clave = valor, por ejemplo

tile.dirt.name=Dirt
advMode.nearestPlayer=Use "@p" to target nearest player

build.tooHigh=Height limit for building is %s blocks

Debe convertirse en un objeto JSON grande con clave = valor

{
    "tile.dirt.name": "Dirt",
    "advMode.nearestPlayer": "Use \"@p\" to target nearest player",
    "build.tooHigh": "Height limit for building is %s blocks"
}

Algunos detalles

  • Se permite cualquier JSON válido siempre que contenga solo los pares clave / valor correctos. Las comas finales están permitidas porque Minecraft las permite.
  • Las únicas cosas que se deben escapar son las comillas. (No existían líneas nuevas, barras diagonales invertidas u otras cosas que rompieran los json en el archivo de idioma antes de 1.13)
  • Las líneas vacías deben ignorarse.
  • Las líneas contienen exactamente uno igual

Casos de prueba

Entrada:

tile.dirt.name=Dirt
advMode.nearestPlayer=Use "@p" to target nearest player

build.tooHigh=Height limit for building is %s blocks

Salida:

{
    "tile.dirt.name": "Dirt",
    "advMode.nearestPlayer": "Use \"@p\" to target nearest player",
    "build.tooHigh": "Height limit for building is %s blocks"
}

Entrada:

translation.test.none=Hello, world!
translation.test.complex=Prefix, %s%2$s again %s and %1$s lastly %s and also %1$s again!
translation.test.escape=%%s %%%s %%%%s %%%%%s
translation.test.invalid=hi %
translation.test.invalid2=hi %  s
translation.test.args=%s %s
translation.test.world=world

Salida:

{
  "translation.test.none": "Hello, world!",
  "translation.test.complex": "Prefix, %s%2$s again %s and %1$s lastly %s and also %1$s again!",
  "translation.test.escape": "%%s %%%s %%%%s %%%%%s",
  "translation.test.invalid": "hi %",
  "translation.test.invalid2": "hi %  s",
  "translation.test.args": "%s %s",
  "translation.test.world": "world",
}

Entrada:

stat.mineBlock=%1$s Mined
stat.craftItem=%1$s Crafted
stat.useItem=%1$s Used
stat.breakItem=%1$s Depleted

Salida:

{
    "stat.mineBlock": "%1$s Mined",
    "stat.craftItem": "%1$s Crafted",
    "stat.useItem": "%1$s Used",
    "stat.breakItem": "%1$s Depleted"
}
pfg
fuente
1
¿Cómo tile.dirt.namellegar a ser "block.minecraft.dirt"?
Pavel el
@Pavel uuh ... whoops. Arreglado eso. Eso no fue intencional
pfg
55
¿Se garantiza que cada línea no vacía contenga exactamente 1 =?
user202729
@ user202729 sí
pfg
3
Estaría dispuesto a apostar que realmente necesita una solución a este problema y tiene la intención de usar una para convertir sus archivos. :)
mbomb007

Respuestas:

4

Python 3, 91 77 bytes

-14 Bytes gracias a OMᗺ

Pensé que la impresión de un diccionario de Python estaría lo suficientemente cerca de JSON para convertirlo en un lenguaje muy competitivo para este desafío. Sin embargo, la representación de cadena de los diccionarios de Python es lo suficientemente diferente de JSON que tuve más suerte usando la biblioteca JSON incorporada de python. Apuesto a que esto se puede hacer de manera más sucinta en JavaScript.

import json
f=lambda x:json.dumps(dict(i.split("=")for i in x.split("\n")if i))

Pruébalo en línea!


Editar:

Bash + Sed, 68 63 bytes

Corrección de errores gracias a OMᗺ y Night 2-5
Bytes gracias a OMᗺ

Me di cuenta de que podría ser más eficiente en bytes convertir directamente el texto a JSON sin agruparlo en un objeto, como fue mi enfoque para la solución de Python. Por byte, sed es el lenguaje más poderoso para el reemplazo de expresiones regulares que conozco.

echo {`echo "$1"|sed 's/"/\\\"/g;s/\(.*\)=\(.*\)/"\1":"\2",/'`}

Pruébalo en línea!

Explicación

echo {`                                  #  prints the leading curly brace
       echo "$1"|sed                     # feeds the input into sed
       's/"/\\"/g;                       # replaces " with \"
       s/\(.*\)=\(.*\)/"\1":"\2",/'      # surrounds the left and right hand sides of the equals with quotes and joins them with a colon
`}                                       # prints the closing curly brace
Algodón Zachary
fuente
8
Si está respondiendo en dos idiomas diferentes, no dude en publicarlo como dos respuestas separadas.
mbomb007
Para la respuesta bash + sed, intente usar el -rindicador para sed (+3 bytes) para que no necesite escapar de los grupos de captura (-4 bytes) tio.run/##LYq7CgIxEEX7/…
user41805
4

Vim, 44 bytes

O{<Esc>:%s/"/\\"/g|%s/\v(.*)\=(.*)/"\1":"\2",
o}

Explicación:

O{<Esc>                                           Prepend {
       :%s/"/\\"/g                                Escape all "
                  |%s/\v(.*)\=(.*)/"\1":"\2",     Json-ify lines
o}                                                Append }
oktupol
fuente
3

Óxido , 150 bytes

|s:String|s.replace('"',"\\\"").split('\n').filter(|l|l.len()>0).map(|l|format!("\"")+&l.replace('=',"\":\"")+"\",").fold(format!("{{"),|r,n|r+&n)+"}"

Pruébalo en línea!

¿Es más largo que Java?

Herman L
fuente
2

Retina 0.8.2 , 35 bytes

"
\"
=
": "
G`.
.+
    "$&",
^
{¶
$
¶}

Pruébalo en línea! Sería de 34 bytes en Retina 1 como puede usar en L$`.+lugar de G`.y .+. Explicación:

"
\"

Escapar de las citas.

=
": "

Arregle el separador clave / valor. (Si el valor puede contener a =, úselo 1`=a un costo de 2 bytes).

G`.

Eliminar líneas vacías.

.+
    "$&",

Envuelva cada línea entre comillas. (Las citas internas se agregaron anteriormente).

^
{¶
$
¶}

Envuelva toda la salida en {}s.

Neil
fuente
2

Casco , 22 bytes

La manipulación de cuerdas no es realmente la fuerza de Husk, pero funcionó bastante bien:

`J"{}"J',mȯJ':msx'=fI¶

Pruébalo en línea!

                      ¶  -- split on newlines
                    fI   -- filter by identity (ie. remove empty strings)
         m(        )     -- with each line
                x'=      -- | split on '='
              ms         -- | show each (ie. enclose in quotes and escape quotes)
           J':           -- | join with ':'
      J',                -- join these with ','
`J"{}"                   -- join the string "{}" with the result
ბიმო
fuente
Irónicamente, ¡hay algo llamado un "Husk" en Minecraft!
Programas Redwolf
2

Ruby , 56 bytes

->x{x.split(?\n).map{|i|i.split(?=)}.to_h.to_json}

+6 bytes para la -rjsonbandera del intérprete.

Pruébalo en línea!

dkudriavtsev
fuente
1
@ Piccolo, ¿pasaste la bandera -rjson?
pfg
@pfg Wow, realmente dejé caer la pelota sobre eso jaja No solo me había olvidado de usar -rjson, sino que también asumí sin verificar que el error era el mismo que había involucrado anteriormenteto_h
Piccolo
2

Perl 5 -nl -M5.010 , 58 54 bytes

BEGIN{say'{'}s'"'\"'g;/=/&&say qq|"$`": "$'",|}{say'}'

Pruébalo en línea!


Versión de 58 bytes:

BEGIN{say'{'}s'"'\"'g;s/(.*)=(.*)/"$1": "$2",/;END{say'}'}

Pruébalo en línea!

sundar - Restablecer a Monica
fuente
Ambas versiones agregan una coma después de cada par clave: valor, que técnicamente no cumple con JSON (la coma final antes del cierre }debe omitirse y fallará con los validadores JSON más estrictos). Aquí hay una rápida reescritura de 58 bytes que produce JSON válido (si es más feo para los lectores humanos): $c||='{';s'"'\"'g;/=/&&say qq|$c"$`":"$'"|;$c=','}{say'}' espero que pueda encontrar algo un poco más corto / más elegante.
ratonera
@mousetrapper Esa es una buena manera de evitar el BEGIN. Sin embargo, OP permite explícitamente las comas finales: "Las comas finales están permitidas porque Minecraft las permite". Siéntase libre de publicar eso como una nueva respuesta, mencionando la diferencia.
sundar - Restablecer Monica
Ah, sí, buen punto, perdí esa frase en la publicación original. La asignación predeterminada solo tiene sentido si está tratando de variar el primer carácter, de lo contrario, su BEGINaún es más corto en el caso en que solo desea emitir el '{'. Me gusta tu ENDtécnica para evitar. Sabía que eso -ncolocaba un bucle efectivo while(<>){} alrededor de su código; No tenía idea de cuán literal era eso.
ratonera
También me sorprendió bastante cuando lo descubrí por primera vez. Es una de esas características de Perl que se extiende a lo largo de la línea entre un truco extraño y una forma brillante de hacer TIMTOWDI. Sin embargo, me había olvidado de él, por lo que el crédito en este caso es para Dennis en el hilo de consejos de golf de Perl 5 .
sundar - Restablece a Mónica el
2

Haskell , 75 71 bytes

-4 bytes gracias a Laikoni (¡usando la notación do sobre la comprensión de la lista)!

Funciona con múltiples =en una línea:

f s='{':do{(a,_:b)<-span(/='=')<$>lines s;show a++':':show b++","}++"}"

Pruébalo en línea!

Explicación

El término span(/='=')<$>lines sdivide la cadena en el primero =, dejándonos con ("<initial part>","=<remaining line>"). Hacer una coincidencia de patrones (a,_:b)asegura que la línea no esté vacía y al mismo tiempo elimina el inicio =.

Ahora solo necesitamos showambos ay b(encerrándolo entre comillas y comillas), formatear ( :y ,caracteres) y finalmente encerrarlo {}.

ბიმო
fuente
1
71 bytes usando do: ¡ Pruébelo en línea!
Laikoni
2

C (gcc) , 243 219 bytes

Gracias a ceilingcat por la sugerencia.

Decidí usar una máquina de estado para manejar los tres casos (nueva línea, clave, valor) y resultó bastante bien. Además, tengo que ab uso de la caída a través de la función switchy el operador stringizing macro!

Aunque el desafío no lo requería, también escapé del \personaje según la especificación JSON. Si ese carácter nunca estará en la entrada, se &&c-92puede eliminar por 5 bytes más.

#define p(s)printf(#s,c)
#define a(i)case i:
c,s;f(){for(p({);(c=getchar())>0;)switch(s){a(0)if(c<11)break;s++,p(\42);a(1)c==61?s++,p(":"):p(%c);break;a(2)c-34&&c-92?c==10?p(\42\54),s=0:p(%c):p(\\%c);}s-2||p(\42);p(});}

Pruébalo en línea!


Envío original: 243 bytes

El envío original mantuvo espacios innecesarios como en los ejemplos JSON proporcionados.

#define p(s)printf(s,c)
#define a(i)case i:
c,s;f(){for(p("{\n");(c=getchar())>0;)switch(s){a(0)if(c<11)break;s++,p("  \"");a(1)c==61?s++,p("\": \""):p("%c");break;a(2)c-34&&c-39?c==10?p("\",\n"),s=0:p("%c"):p("\\%c");}s==2&&p("\"\n");p("}");}

Pruébalo en línea!

ErikF
fuente
2

JavaScript, 66 63 62 bytes

s=>JSON.stringify(o=/(.+)=(.+)/g,s.replace(o,(_,a,b)=>o[a]=b))

-3 bytes gracias a @redundancy

-1 byte gracias a @ l4m2

Darrylyeo
fuente
63 bytes en TIO
redundancia
@ l4m2 objetos StrExified RegExp? Aprendí algo nuevo hoy 🤯
darrylyeo
1

Perl 6 , 48 bytes

{to-json %(.lines.grep(?*)>>.split("=",2).flat)}

2 bytes menos si podemos suponer exactamente 1 signo igual en una línea no vacía.

Pruébalo en línea!

Sin golf:

{                   # An anonymous block, taking 1 string which ends in $_.
    to-json         # Convert a Perl 6 number, string, list or hash to JSON and return it.
    %(              # Force to hash (dictionary)
        .lines      # Break $_ (implicitly assumed) into a list of lines.
        .grep(?*)   # Pick only those that are True (non-empty).
        >>.         # For each element in the list, call the following method ... 
        split("=",2) # ... split the string at =, making at most 2 chunks.
        .flat       # That gives a list of 2-element lists. Flatten it.
    )               # List is converted into the hash like this: { first element => second element, third => fourth, ... }
}                   # Implicitly return

Por cierto, la to-jsonrutina está en desuso, como el compilador le dirá, pero a quién le importa.

Ramillies
fuente
1

Rubí, 59 + 5 = 64

Necesidades -rjson(+5)

->c{Hash[*c.split(?\n).map{|l|l.split ?=}.flatten].to_json}

Explicación:

->c{                                                      } # anonymous function with param c
    Hash[*                                       ]          # converts ["a", "b", "c", "d"] into {"a": "b", "c": "d"}
          c.split(?\n)                                      # splits c into lines
                      .map{|l|          }                   # map lines so each element represents
                              l.split ?=                    # an array of itself but split by =
                                         .flatten           # merges 2d array to 1d (also gets rid of empty elements for newlines
                                                  .to_json  # converts hash to json
Piccolo
fuente
1

JavaScript (ES6), 66 bytes

s=>`{${s.replace(/"/g,'\\"').replace(/(.*)=(.*)/g,'"$1":"$2",')}}`

Asume que solo hay uno =por línea

Fragmento de prueba

f=s=>`{${s.replace(/"/g,'\\"').replace(/(.*)=(.*)/g,'"$1":"$2",')}}`
<textarea id="i" onkeyup="o.innerText=f(i.value)"></textarea><pre id="o">

Herman L
fuente
Debería tener 66 bytes. \\ podría haber sido analizado como \ al contar la longitud.
redundancia
1
@redundancy Realmente debería dejar de usar "code".lengthen la consola javascript para contar la longitud
Herman L
1

V , 30 bytes

O{␛Í"/\\"
ggòeÉ"vyf=Plp$pa,òo}

Espera una entrada a la vez. El fragmento TIO ejecuta todos los casos de prueba dados como una sola entrada.

Soy nuevo en las asignaciones extendidas de V, ¡así que los consejos siempre son bienvenidos!

Pruébalo en línea!

Explicación

O{␛                  # insert { on a new line above
   Í                 # global substitution across all lines
    "/\\"            #   " => \"
gg                   # go to first line
  ò                  # recursively...
   e                 #   forward to end of word; if at end of line, applies to next word below
    É"               #   prepend " to first non-whitespace char
      vy             #   copy current character (i.e. ")
        f=Plp        #   paste " before and after the next =
             $pa,    #   paste " at end of line and append ,
                 ò   # ...end
                  o} # insert } on a new line below
redundancia
fuente
1

C (gcc) , 172 bytes

#define p(s)printf(#s,c)
c,s;f(){for(p({);~(c=getchar());)s-2?c>10|s&&(s||(s+=p(\42)),c==61?s++,p(":"):p(%c)):c-34&&c-92?c==10?s=!p(\42\54):p(%c):p(\\%c);s-2||p(\42);p(});}

Pruébalo en línea!

Basado en la implementación de @ ErikF pero sin ella switch/case.

Versión ligeramente no golf

#define p(s)printf(#s,c)
c,s;
f(){
 for(p({);~(c=getchar());)
  s-2?
   c>10|s&&(
    s||
     (s+=p(\42)),
    c==61?
     s++,
     p(":")
    :
     p(%c)
   )
  :
   c-34&&c-92?
    c==10?
     s=!p(\42\54)
    :
     p(%c)
   :
    p(\\%c);
 s-2||p(\42);
 p(});
}
techo
fuente
1

R, 118 bytes

function(s){cat(paste("{",gsub("(.*)=(.*)","\"\\1\":\"\\2\",",gsub("\"","\\\\\"",gsub("\n{2,}","\n",s)),perl=T),"}"))}

Pruébalo en línea!

Chaos Manor
fuente
1

C (gcc) , 119 bytes

#define p(s)printf(#s,c)
s;f(c){for(p({);~(c=getchar())|s;)c<11?s=s&&!p(",�"):c-61?s++||p(\42),p(\\u%04x):p(":");p(});}

Pruébalo en línea!

l4m2
fuente
1

PHP, 87 bytes

preg_match_all("/^(.*)=(.*)$/m",$argn,$m);echo json_encode(array_combine($m[1],$m[2]));

Ejecutar como tubería -nRo probarlo en línea .

Insertar \santes $/mpara los saltos de línea de Windows; \s*si los saltos de línea son inciertos.
Insertar Udespués $/msi los valores contienen =.

Titus
fuente
1

Dart , 142 114 108 bytes

f(s)=>"""{${s.replaceAll('"','\\"').replaceAllMapped(RegExp(r'(.*)=(.*)'),(m)=>'"${m[1]}":"${m[2]}",')}}""";

Pruébalo en línea!

  • -28 bytes al deshacerse de la función json.encode y usar la construcción de cadenas regular
  • -6 bytes eliminando la palabra clave 'nueva' y algunos espacios
  • Elcan
    fuente