Sangría inversa

63

Escuché que su código puede ejecutarse más rápido si lo sangra al revés, de modo que el compilador pueda procesarlo como un patrón de diseño de árbol desde la parte superior de las "ramas" hacia abajo. Esto ayuda porque la gravedad acelerará el tiempo que toma compilar su código y la eficiencia de la estructura de datos mejora. Aquí hay un ejemplo, en las secuencias de comandos Java:

            function fib(n) {
        var a = 1, b = 1;
        while (--n > 0) {
    var tmp = a;
    a = b;
    b += tmp;
    if (a === Infinity) {
return "Error!";
    }
        }
        return a;
            }

Pero por alguna razón, el Bloc de notas no tiene una configuración para hacer esto automáticamente, por lo que necesito un programa que lo haga por mí.

Descripción

Las presentaciones deben tomar un fragmento de código como entrada, revertir la sangría y generar el código resultante.

Esto se realiza mediante el siguiente procedimiento:

  • Divide el código en líneas. Cada línea comenzará con cero o más espacios (no habrá pestañas).

  • Encuentra todos los niveles de sangría únicos en el código. Por ejemplo, para el ejemplo anterior, esto sería

    0
    4
    8
    12
    
  • Invierta el orden de esta lista de niveles de sangría y asigne la lista invertida a la lista original. Esto es difícil de explicar con palabras, pero por ejemplo, se vería como

    0  — 12
    4  — 8
    8  — 4
    12 — 0
    
  • Aplique esta asignación al código original. En el ejemplo, una línea con sangría de 0 espacios quedaría sangrada por 12 espacios, 4 espacios se convertirían en 8 espacios, etc.

De entrada y salida

La entrada y la salida se pueden proporcionar como desee (STDIN / STDOUT, parámetro de función / valor de retorno, etc.); Si su idioma no admite entrada de |líneas múltiples (o simplemente no desea), puede usar el carácter para separar las líneas.

La entrada consistirá solo en nuevas líneas ASCII + imprimibles, y no contendrá líneas vacías.

Casos de prueba

Entrada:

function fib(n) {
    var a = 1, b = 1;
        while (--n > 0) {
            var tmp = a;
            a = b;
            b += tmp;
            if (a === Infinity) {
                return "Error!";
            }
        }
    return a;
}

Salida: el código de ejemplo anterior.

Entrada:

a
  b
  c
d
   e
        f
  g
   h

Salida:

        a
   b
   c
        d
  e
f
   g
  h

Entrada:

1
 2
  3
 2
1

Salida:

  1
 2
3
 2
  1

Entrada:

  foo

Salida:

  foo
Pomo de la puerta
fuente
21
Su "JavaScript" no "Java scripting": /
Optimizer
75
@Optimizer Veo que mi objetivo de enfurecer a tantas personas como sea posible con los dos primeros párrafos se ha logrado. ;)
Pomo de la puerta
77
1! = Tantas personas como sea posible.
Optimizador
23
@ JanDvorak Los mismos tipos que inventaron las citas de estilo MLA piensan que es una buena idea.
Rainbolt
66
Supuestamente, es más rápido. Asignemos un comité y esperemos unos años mientras olvidamos su propósito.
Conor O'Brien

Respuestas:

10

CJam, 43 39 36 35 bytes

qN/_{_Sm0=#}%___&$_W%er]z{~S*@+>N}%

Esto parece demasiado largo. ¡Estoy seguro de que no estoy optimizando lo suficiente!

Cómo funciona:

La idea básica es dividir la entrada en la nueva línea, calcular el número de espacios iniciales en cada línea, ordenar y obtener números únicos, copiar esa matriz e invertir la copia, transliterar los números originales en orden con estas dos matrices y finalmente formar el cadena final con esta información.

La parte más larga es averiguar cuántos espacios iniciales hay en cada línea, ya que CJam no tiene una manera fácil de hacerlo.

Expansión de código:

qN/_                                      "Split the string on newline and take copy";
    {_Sm0=#}%                             "Map this code block on the copy";
     _Sm                                  "Copy the string and remove spaces from the copy";
        0=                                "Get first non space character";
          #                               "Gets its index in original string";
             ___                          "Get 3 copies of the above array";
                &$_W%                     "Get unique elements, sort, copy and reverse";
                     er                   "Transliterate unique sorted elements with";
                                          "the unique reverse sorted in the copy";
                       ]z                 "Get array of [row,
                                          " original number of leading spaces,
                                          " required number of leading spaces]";
                         {~S*@+>N}%       "For each above combination";
                          ~S*             " unwrap and get leading space string";
                             @+           " prepend to the row";
                               >          " remove original spaces";
                                N         " put newline";

Y en el espíritu de la pregunta. Una verdadera expansión del código:

                                          qN/_                                      "Split the string on newline and take copy";
                                {_Sm0=#}%                             "Map this code block on the copy";
                               _Sm                                  "Copy the string and remove spaces from the copy";
                             0=                                "Get first non space character";
                          #                               "Gets its index in original string";
                         ___                          "Get 3 copies of the above array";
                       &$_W%                     "Get unique elements, sort, copy and reverse";
                     er                   "Transliterate unique sorted elements with";
"the unique reverse sorted in the copy";
                ]z                 "Get array of [row,
" original number of leading spaces,
" required number of leading spaces]";
             {~S*@+>N}%       "For each above combination";
          ~S*             " unwrap and get leading space string";
        @+           " prepend to the row";
     >          " remove original spaces";
    N         " put newline";

7 bytes guardados gracias a Martin y 1 byte gracias a Dennis

Pruébalo en línea aquí

Optimizador
fuente
1. {}#tiene un error: devuelve un entero, pero debería devolver un largo. Irónicamente, i(convertir a entero) arregla esto. 2. Como ""#no tiene el mismo error, _Sm0=#es un byte más corto.
Dennis
@ Dennis Sí, el error es extraño. Gracias por la solución!
Optimizador
2
¡Esta sangría en la expansión es tan fácil de leer! ¡Deberías revertirlo!
DLeh
13

Python 2 - 137 131 bytes

i=raw_input().split('|')
f=lambda s:len(s)-len(s.lstrip())
d=sorted(set(map(f,i)))
for l in i:print' '*d[~d.index(f(l))]+l.lstrip()

Toma entrada con en |lugar de \n.

Explicación

Las primeras tres líneas son bastante sencillas. Haga una lista de todas las líneas en la entrada, defina una función que le indique cuánto espacio en blanco inicial tiene una cadena y haga una lista ordenada de valores que la función escupe para cada línea de entrada.

La última línea es mucho más divertida.

                                 l               # string with the line
                               f(l)              # amount of leading whitespace
                       d.index(f(l))             # where it is in list of whitespace amounts
                      ~d.index(f(l))             # bitwise NOT (~n == -(n+1))
                    d[~d.index(f(l))]            # index into the list (negative = from end)
           print' '*d[~d.index(f(l))]            # print that many spaces...
           print' '*d[~d.index(f(l))]+l.lstrip() # plus everything after leading whitespace
for l in i:print' '*d[~d.index(f(l))]+l.lstrip() # do the above for every line
metro subterráneo
fuente
Confirmado 137 :)
FryAmTheEggman
@frya gracias :)
undergroundmonorail
1
Todo esto parece estar bien en Python 3, que debería ahorrarle 2 bytes (pague 2 por ()guardar 4 raw_)
FryAmTheEggman
1
f(s)for s in idebería ser map(f,i).
feersum
1
Un pedazo de magia: d=[];d+=set(L)es una versión más corta de d=sorted(set(L)).
xnor
7

JavaScript, ES6, 113 103 101 bytes

Estoy bastante seguro de que esto se puede jugar al menos un poco más, pero aquí va.

¡Nunca hubiera pensado que habrá una solución JS de 101 bytes, superando a Python!

f=a=>(b=c=[...Set(a.match(r=/^ */gm).sort())],c.map((x,i)=>b[x]=c.slice(~i)[0]),a.replace(r,x=>b[x]))

Esto crea un método llamado fque se puede llamar con la cadena de entrada. Si tiene una versión más reciente de Firefox, tiene cadenas de plantilla y puede llamar al método como

f(`a
  b
  c
d
   e
        f
  g
   h`)

De lo contrario, también puede llamarlo como

f("a\n\
  b\n\
  c\n\
d\n\
   e\n\
        f\n\
  g\n\
   h")

o prueba el fragmento a continuación:

g=_=>O.textContent=f(D.value)

f=a=>(b=c=[...Set(a.match(r=/^ */gm).sort())],c.map((x,i)=>b[x]=c.slice(~i)[0]),a.replace(r,x=>b[x]))
<textarea id=D></textarea><button id=B onclick=g()>Inverse!</button>
<pre id=O></pre>

Optimizador
fuente
Puede guardar los bytes de un cupé almacenando la expresión regular como una variable, ya que se usa dos veces (debe poder reemplazar \scon un carácter de espacio) y eliminando los paréntesis xen la función de reemplazo.
NinjaBearMonkey
@hsl gee, gracias! Ni siquiera sé por qué escribí (x): /
Optimizer
No es necesario tanto by c¿verdad? Simplemente se refieren a la misma matriz de todos modos.
Neil
5

Ruby, 63 bytes

->s{l=s.scan(r=/^ */).uniq.sort;s.gsub r,l.zip(l.reverse).to_h}

Esto define una función sin nombre que toma y devuelve una cadena. Puede llamarlo agregando ["string here"]o asignándolo a una variable, y luego llamando a esa variable.

Cómo funciona: s.scan(r=/^ */)proporciona una lista de todos los espacios y tiendas principales que se regexan rpara su uso posterior. uniqelimina duplicados sort... clases.

Ahora salte al final, l.zip(l.reverse)da una serie de pares que queremos sustituir. to_hconvierte eso en un hash, interpretando los pares como pares clave-valor.

Ahora s.gsubreemplazó todas las coincidencias de la expresión regular (todos los espacios iniciales) utilizando ese hash como una tabla de búsqueda para encontrar el reemplazo.

Martin Ender
fuente
2

Japt -R , 27 bytes

·
mâ\S
Vâ n
Ëx2 iSpWg~WbVgE

Pruébalo en línea!

Desempaquetado y cómo funciona

Input: U = multiline string

qR    Split by newline and implicit assign to U

mâ\S
m     Map over U...
 â\S    .search(/\S/); first index of non-whitespace char
      Implicit assign to V (V = array of indentations)

Vâ n  Take unique elements of V, sort, and implicit assign to W

mDEF{Dx2 iSpWg~WbVgE
mDEF{                 Map over U...
     Dx2                Trim left
         iSp            Indent by this many spaces...
                 VgE      Find the current indentation stored in V
               Wb         Find its index on W
            Wg~           Take the opposite element on W

-R    Join with newline

Cómo funciona realmente

                 Input: U = multiline string

                 qR    Split by newline and implicit assign to U

                 mâ\S
                 m     Map over U...
               â\S    .search(/\S/); first index of non-whitespace char
         Implicit assign to V (V = array of indentations)

                 Vâ n  Take unique elements of V, sort, and implicit assign to W

                 mDEF{Dx2 iSpWg~WbVgE
                 mDEF{                 Map over U...
            Dx2                Trim left
      iSp            Indent by this many spaces...
VgE      Find the current indentation stored in V
 Wb         Find its index on W
     Wg~           Take the opposite element on W

                 -R    Join with newline
Bubbler
fuente
1

Scala, 176 171

def g(n:String)={val a=n.split('|').map(a=>a.prefixLength(' '==)->a)
(""/:a){case(s,(l,p))=>val b=a.unzip._1.distinct.sorted
s+" "*b.reverse(b.indexOf(l))+p.drop(l)+'\n'}}

Agregará una nueva línea adicional al final. Si no tuviera que preservar espacios al final de la línea, puedo llegar a 167:

def t(n:String)={val a=n.split('|').map(a=>a.prefixLength(' '==)->a.trim)
(""/:a){(s,l)=>val b=a.unzip._1.distinct.sorted
s+" "*b.reverse(b.indexOf(l._1))+l._2+'\n'}}

Sin golf:

      def reverseIndent(inString: String): String = {
    val lines = inString.split('\n')
    val linesByPrefixLength = lines.map { line =>
  line.prefixLength(char => char == ' ') -> line
    }
    val distinctSortedPrefixLengths = linesByPrefixLength.map(_._1).distinct.sorted
    val reversedPrefixes = distinctSortedPrefixLengths.reverse
    linesByPrefixLength.foldLeft("") { case (string, (prefixLength, line)) =>
  val newPrefixLength = reversedPrefixes(distinctSortedPrefixLengths.indexOf(prefixLength))
  val nextLinePrefix = " " * newPrefixLength
  string + nextLinePrefix + line.substring(prefixLength) + '\n'
    }
      }
Chad Retz
fuente
1

PowerShell , 112 bytes

$x=@($args|sls '(?m)^ *'-a|% m*|% v*|sort -u)
[regex]::Replace($args,'(?m)^ *',{$x[-1-$x.IndexOf($args.Value)]})

Pruébalo en línea!

Menos golfizado:

$xIdents=@($args|select-string '(?m)^ *'-AllMatches|% matches|% value|sort -unique) # get a sorted set of indentations
[regex]::Replace($args,'(?m)^ *',{$xIdents[-1-$xIdents.IndexOf($args.Value)]})    # replace each indentation with opposite one
mazzy
fuente
0

Haskell, 116

import Data.List
f s|l<-map(span(==' '))$lines s=unlines[k++b|(a,b)<-l,(k,r)<-reverse>>=zip$sort$nub$map fst l,r==a]
orgulloso Haskeller
fuente
0

PHP - 173 bytes

El código no optimizado debe almacenarse en la $vvariable:

<?php $f='preg_replace';$f($p='#^ *#me','$i[]='.$s='strlen("$0")',$v);$a=$b=array_unique($i);sort($a);rsort($b);echo$f($p,'str_repeat(" ",array_combine($a,$b)['.$s.'])',$v);

Aquí está la versión no comentada y comentada:

<?php
// Get the level of indentation for each line
$preg_replace = 'preg_replace';
$pattern = '#^ *#me';
$strlen = 'strlen("$0")';
$preg_replace($pattern, '$indentationLevelsOldList[] = '. $strlen, $value);

// Create an array associating the old level of indentation with the new expected one
$sortedArray = array_unique($indentationLevelsOldList);
$reverseSortedArray = $sortedArray;

sort($sortedArray);
rsort($reverseSortedArray);

$indentationLevelsNewList = array_combine($sortedArray, $reverseSortedArray);

// Print the correctly indented code
echo $preg_replace($pattern, 'str_repeat(" ", $indentationLevelsNewList['. $strlen .'])', $value);

Probablemente nunca haya escrito algo tan sucio. Estoy avergonzado.

Agujero negro
fuente
0

JavaScript, 351

var i=0;var a=$("#i").html().split("\n");var b=[];for(;i<a.length;i++){j=a[i].match(/\s*/)[0];if(b.indexOf(j)<0){b.push(j);}}b.sort(function(a,b){return a - b;});var c=b.slice().reverse();var d="";for(i=0;i<a.length;i++){d+=a[i].replace(/\s*/,c[b.indexOf(a[i].match(/\s*/)[0])])+"\n";j=a[i].search(/\S/);if(b.indexOf(j)<0){b.push(j);}}$("#i").html(d);

Versión sin golf:

var i = 0;
var a = $("#i").html().split("\n");
var b = [];
for (; i < a.length; i++) {
  j = a[i].match(/\s*/)[0];
  if (b.indexOf(j) < 0) {
    b.push(j);
  }
}
b.sort(function(a, b) {
  return a - b;
});
var c = b.slice().reverse();
var d = "";
for (i = 0; i < a.length; i++) {
  d += a[i].replace(/\s*/, c[b.indexOf(a[i].match(/\s*/)[0])]) + "\n";
  j = a[i].search(/\S/);
  if (b.indexOf(j) < 0) {
    b.push(j);
  }
}
$("#i").html(d);

Pruebas

El chico con el sombrero
fuente
0

Perl 5, 112

111 + 1 para -n( -Ees gratis)

@{$.[$.]}=/( *)(.*)/;++$_{$1}}{map$_{$_[$#_-$_]}=$_[$_],0..(@_=sort keys%_);say$_{$.[$_][0]}.$.[$_][1]for 0..$.

Estoy seguro de que se puede hacer con menos golpes, pero no veo cómo en este momento.

msh210
fuente