Fin de las pestañas versus guerra espacial


24

Fin de las pestañas versus guerra espacial

Por lo tanto, se ha debatido mucho sobre si usar pestañas o espacios para sangrar / formatear código. ¿Puedes ayudar a la universidad a resolver la disputa yendo a un método de formateo increíblemente loco ?


Su trabajo es escribir un programa o función completa que expanda todas las pestañas en cuatro espacios. Y luego reemplaza una serie de n espacios iniciales con "/ (n - dos estrellas aquí) /". Recibirá información sobre varias líneas en cualquier formato razonable (matriz de cadenas de una sola cadena para cada nueva línea. Matriz de columnas, etc.)

Entrada de muestra robada descaradamente . Tenga en cuenta que, dado que las pestañas se expanden automáticamente a cuatro espacios en SE, lo represento como el carácter "^", pero también debe manejar las pestañas (punto de código 0x09). Todos los caracteres "^" representan una tabulación.

Calculate the value 256 and test if it's zero
If the interpreter errors on overflow this is where it'll happen
++++++++[>++++++++<-]>[<++++>-]
+<[>-<
    Not zero so multiply by 256 again to get 65536
    [>++++<-]>[<++++++++>-]<[>++++++++<-]
    +>[>
        # Print "32"
        ++++++++++[>+++++<-]>+.-.[-]<
    <[-]<->] <[>>
        # Print "16"
        +++++++[>+++++++<-]>.+++++.[-]<
<<-]] >[>
    # Print "8"
    ++++++++[>+++++++<-]>.[-]<
<-]<
# Print " bit cells\n"
+++++++++++[>+++>+++++++++>+++++++++>+<<<<-]>-.>-.+++++++.+++++++++++.<.
>>.++.+++++++..<-.>>-
Clean up used cells.
[[-]<]l
^this is preceded by a tab
^^two tabs
^^^three tabs etcetera! 

Salida de muestra

Calculate the value 256 and test if it's zero
If the interpreter errors on overflow this is where it'll happen
++++++++[>++++++++<-]>[<++++>-]
+<[>-<
/**/Not zero so multiply by 256 again to get 65536
/**/[>++++<-]>[<++++++++>-]<[>++++++++<-]
/**/+>[>
/******/# Print "32"
/******/++++++++++[>+++++<-]>+.-.[-]<
/**/<[-]<->] <[>>
/******/# Print "16"
/******/+++++++[>+++++++<-]>.+++++.[-]<
<<-]] >[>
/**/# Print "8"
/**/++++++++[>+++++++<-]>.[-]<
<-]<
# Print " bit cells\n"
+++++++++++[>+++>+++++++++>+++++++++>+<<<<-]>-.>-.+++++++.+++++++++++.<.
>>.++.+++++++..<-.>>-
Clean up used cells.
[[-]<]l
/**/this is preceded by a tab
/******/two tabs
/**********/three tabs etcetera! 

Debido a que la universidad necesita espacio para descargar tanto Vim como Emacs, se le permite muy poco almacenamiento para su código. Por lo tanto, este es el y gana el código más corto. Puede suponer que la entrada está bien formada y que las líneas con menos de cuatro espacios (después del reemplazo de pestañas) pueden dar lugar a un comportamiento indefinido.

Renuncia

Esta estrategia de formato "excelente" surgió por cortesía de Geobits y se reproduce con su permiso. Ningún programador resultó dañado durante la producción de este desafío.


1
¿Las pestañas solo aparecerán al comienzo de las líneas (es decir, como sangría)? ¿Pueden las líneas tener sangría mixta (tabulaciones + espacios)?
Lynn

20
Alguien por favor envíe una respuesta escrita en espacios en blanco .
GuitarPicker

2
¿Deberíamos considerar las líneas que comienzan con /*, o se puede suponer que no es una "entrada bien formada"? Un archivo fuente de C ++ habría sido una mejor prueba, porque su comentario multilínea /* */posiblemente rompería algunas respuestas que reemplazan primero y último de los espacios iniciales con an /, y luego proceda a llenar espacios con *.
seshoumara

1
La guerra ha terminado: medium.com/@hoffa/… (a menos que esté programando en C, aparentemente.)
vaso de precipitados el

1
@RohanJhunjhunwala Así que ahora hago mi primera pregunta nuevamente, ya que no se trataba de código compilable. Imagine el mismo /* */código C ++, pero esta vez al principio de la línea. Según su especificación, debe dejarse como está. Aquí la trampa es, y ya detectó respuestas incorrectas, que una expresión regular como, por ejemplo, /\** /utilizada para llenar esos espacios entre // con asteriscos convertiría la línea /***/. También he visto esta conversión /*//*/. Asumo que ambos son incorrectos.
seshoumara

Respuestas:


2

V , 21 , 20 bytes

Íô/    
Î^hr/hv0r*r/

Pruébalo en línea!

Esto es literalmente solo un puerto directo de mi respuesta vim. Las diferencias notables:

  • El Ícomando (sustituto global) rellena automáticamente la /gbandera, lo que ahorra dos bytes

  • ô es idéntico a \t

  • ÎEs un mnemónico para :%norm, y también llena el espacio necesario entre :%normy el conjunto de pulsaciones de teclas.

  • El retorno del carro final al final se agrega implícitamente.


27

Vim, 37, 34, 33, 32 bytes

:%s/\t/    /g|%norm ^hr/hv0r*r/

Pruébalo en línea!

Tenga en cuenta que esto requiere un retorno de carro final (enter) en vim, aunque no en el intérprete en línea.

Esto utiliza el intérprete de V porque es compatible con versiones anteriores. Una solución muy sencilla.

Aquí hay un gif que te permite ver la solución en tiempo real. Utiliza una versión un poco más antigua, y agregué algunas pulsaciones de teclas adicionales para que se ejecute más lentamente para que pueda ver lo que sucede:

ingrese la descripción de la imagen aquí

Y aquí está la explicación de cómo funciona:

:%s/\t/    /g           "Replace every tab with 4 spaces
|                       "AND
%norm                   "On every line:
      ^                 "  Move to the first non-whitespace char
       h                "  Move one character to the left. If there is none, the command will end here.
         r/             "  Replace it with a slash
           h            "  Move to the left
            v0          "  Visually select everything until the first column
              r*        "  Replace this selection with asterisks
                r/      "  Replace the first character with a slash

g
Iba

@ Downgoat Jaja, gracias! De hecho, estoy mucho más orgulloso de la versión :gporque abusa de una característica menos conocida: el normcomando se cancela si ^F<space>falla. Entonces, :%norm ^F<space>fooes esencialmente lo mismo que los :g/^ /norm foodivertidos trucos de Vim. : D
DJMcMayhem

eh, pensé que ^ F se usaba para colocar la pantalla. ¿Tiene un comportamiento diferente dentro norm?
Downgoat

1
@ Downgoat Jaja, no ^F, no, <C-f>notación clave de Silly Vim. En este caso es ^, salta al primer carácter que no sea un espacio en blanco, y F<space>que es encontrar el primer espacio detrás del cursor.
DJMcMayhem

ohhh, eso tiene mucho más sentido ahora> _>
Downgoat

11

Perl, 41 bytes

s,␉,    ,g;s,^  ( +),/@{[$1=~y| |*|r]}/,

Corre con la -pbandera, así:

perl -pe 's,␉,    ,g;s,^  ( +),/@{[$1=~y| |*|r]}/,'
#     ↑   └───────────────────┬───────────────────┘
#     1 byte               40 bytes

Reemplazar por una pestaña (en Bash, intente escribir Control-V Tab).


1
El camino perlreemplazó esa referencia en el lugar, desearía sedtener eso también.
seshoumara

7

Cheddar , 60 57 56 bytes

Guardado 3 bytes gracias a @Conor O'Brien

@.sub(/\t/g," "*4).sub(/^ +/gm,i->"/"+"*"*(i.len-2)+"/")

Ojalá Cheddar tuviera un mejor formato de cadena.

Pruébalo en línea!

Explicación

Esta es una función. @es una propiedad representada funcionalizada (por ejemplo, ruby &:) que le permite hacer cosas como: `ar.map (@. head (-1))

@                      // Input
 .sub( /\t/g, " "*4)   // Replace tabs with four spaces
 .sub(
   /^ +/gm,            // Regex matches leading spaces
   i ->                // i is the matched leading spaces
     "/"+              // The / at the beginning
     "*"*(i.len-2)+    // Repeat *s i-2 times
     "/"                // The / at the end
 )

Si no está familiarizado con regex, el:

/^ +/gm

Esto básicamente coincidía con uno o más ( +) espacios ( ) al principio ( ^) de cada ( g) línea ( m).


Cómo funcionan las pestañas literales en expresiones regulares cheddar? Además, es /^ +/suficiente como expresión regular, ya que podemos suponer que los espacios iniciales tendrán al menos 4 de longitud.
Conor O'Brien el

@ ConorO'Brien Creo que lo hacen pero no lo he probado
Downgoat

Se supone que las pestañas deben reemplazarse antes de la transformación.
Conor O'Brien

@ ConorO'Brien oh> _> Lo tenía así originalmente y luego lo cambié
Downgoat

6

Mathematica, 97 bytes

a=StringReplace;a[a[#,"\t"->"    "],StartOfLine~~b:" "..:>"/"<>Table["*",StringLength@b-2]<>"/"]&

Función anónima. Toma una cadena como entrada y devuelve una cadena como salida.


5

Python 3, 124 bytes

Utiliza una buena expresión regular.

import re
lambda I:re.sub('^\s*(?m)',lambda m:'/'+'*'*len(m.group()[:-2])+'/',re.sub('\t+',lambda g:' '*4*len(g.group()),I))

Ideone it!


4

Java 210 207 bytes

Esta es la solución de referencia que lo implementa ingenuamente.

void a(String[]a){for(String s:a){s=s.replaceAll("\t", "    ");String x,y="";int j,i=s.length()-(x=s.replaceAll("^\\s+", "")).length();if(i>3){y="/";for(j=0;j++<i-1;)y+="*";y+="/";}System.out.println(y+x);}}

66
Vim: 37 bytes, Cheddar: 65 bytes, JavaScript: 75 bytes, luego está Java a 210 bytes: P ¿por qué no me sorprende
Downgoat

1
Código muy conciso en Java: P
Rohan Jhunjhunwala

Puede cambiar el último ciclo for para salvar 1 byte: for(int j=0;++j<i-1;). Además, puede eliminar el int antes jy ponerlo después del int ya presente:int i=s.length()-(x=s.replaceAll("^\\s+", "")).length(),j;
Kevin Cruijssen

¿No puede ser una lambda para afeitar bytes usando (a) -> {...}?
bunyaCloven

Al menos todavía es legible y no necesita más comentarios: o)
René

3

JavaScript ES6, 75 bytes

s=>s.replace(/\t/g,"    ").replace(/^ +/gm,k=>`/${"*".repeat(k.length-2)}/`)

Reemplace \tcon una pestaña literal en su código.


3

Java, 185 184 167 152 bytes

S->S.map(s->{s=s.replace("\t","    ");String t=s.replaceAll("^ +","");int n=s.length()-t.length();if(n>3){s="/";for(;n-->2;)s+="*";s+="/"+t;}return s;})

Dada la definición muy suelta de matriz de cadenas dada en la publicación inicial, la he usado, lo Stream<String>que permite algunos ahorros de bytes consecuentes.

Utilicé diferentes técnicas que RI para lograr el mismo objetivo. El algoritmo en sí es bastante el mismo.

Pruebas y sin golf :

import java.util.Arrays;
import java.util.stream.Stream;

public class Main {

  public static void main(String[] args) {
    StringStreamTransformer sst = lines -> lines.map(line -> {
      line = line.replace("\t","    ");
      String trimmed = line.replaceAll("^ +", "");
      int startingSpaces = line.length() - trimmed.length();
      if (startingSpaces > 3) {
        line = "/";
        for(;startingSpaces > 2; startingSpaces--) {
          line += "*";
        }
        line += "/" + trimmed;
      }
      return line;
    });


    Stream<String> lines = Arrays.stream(new String[]{
      "lots of spaces and tabs after\t\t    \t\t         \t\t\t\t\t",
      "no space",
      " 1 space",
      "  2 spaces",
      "   3 spaces",
      "    4 spaces",
      "     5 spaces",
      "      6 spaces",
      "       7 spaces",
      "        8 spaces",
      "\t1 tab",
      "\t\t2 tabs",
      "\t\t\t3 tabs"
    });
    sst.map(lines).map(s -> s.replace(" ", ".").replace("\t","-")).forEach(System.out::println);


  }
}

2

Retina , 25 bytes

El \tdebe ser reemplazado con un carácter de tabulación real (0x09).

\t
4$* 
%`^  ( +)
/$.1$**/

Pruébalo en línea!

Explicación

\t
4$* 

Reemplace cada pestaña con cuatro espacios.

%`^  ( +)
/$.1$**/

Transforme cada línea por separado ( %) haciendo coincidir los 2+Nespacios al comienzo de la línea y reemplazándola por /.../donde ...hay Ncopias de *.



2

SED (56 + 1 para -r) 57

s/⇥/    /g;tr;:r;s,^ ( *) ,/\1/,;T;:l;s,^(/\**) ,\1*,;tl

Dónde hay una pestaña
1. reemplaza las pestañas con espacios.
2. reemplaza el primer y último espacio inicial con /.
3. reemplaza el primer espacio después /y 0+ *s con un *hasta que no haya una coincidencia.


Como se especifica sed, no se necesitan comillas simples alrededor del código, lo mismo que eliminar -r '' de sus otras respuestas sed, porque puede considerar que el script está almacenado en un archivo fuente con el que se ejecuta -f. Cualquier indicador adicional utilizado como nor debería contarse como un byte cada uno. Por lo tanto, aquí guarda 2 bytes.
seshoumara

Eso es lo que pensaba, pero quiero estar seguro. Gracias.
Riley

El ;comando después de t tampoco es necesario. En cuanto al código en sí, necesita un ^ al comienzo del tercer scomando, de lo contrario, una entrada como esta "3/5" se convierte en "3 / * 5". En el primer scomando, en realidad tiene una pestaña allí, pero no se muestra correctamente y es engañosa, así que use \ t o especifique después, que char era una pestaña.
seshoumara

@seshoumara Gracias, estoy tratando de publicar desde mi teléfono ... No es lo más fácil de hacer.
Riley

Creo que pasé más tiempo editando esta respuesta que todas las demás combinadas. ¡Gracias por la ayuda!
Riley

1

La universidad debería considerar permitir un poco más de espacio para los programas en Emacs Lisp (o por defecto tabifyy untabifysolo), ya que se vuelven aún más detallados que Java. También debe prestar mucha atención a los estudiantes (o maestros) cuyo tamaño de ideación es menor a cuatro o que codifican en un lenguaje no similar a C.

La siguiente solución tiene 206 bytes

(lambda (b e)(let((tab-width 4))(untabify b e)(goto-char b)(while(re-search-forward"^ +"e t)(replace-match(format"/%s/"(apply'concat(mapcar(lambda(x)"*")(number-sequence 1(-(length(match-string 0))2)))))))))

Suponiendo que tab-widthno es necesario establecerlo explícitamente, podemos guardar 20 de ellos.

(lambda(b e)(untabify b e)(goto-char b)(while(re-search-forward"^ +"e t)(replace-match(format"/%s/"(apply'concat(mapcar(lambda(x)"*")(number-sequence 1(-(length(match-string 0))2))))))))

Y la versión sin golf se vería así

(defun end-tab-war (beg end)
  (let ((tab-width 4))
    (untabify beg end)
    (goto-char beg)
    (while (re-search-forward "^ +" end t)
      (replace-match
       (format
        "/%s/"
        (apply 'concat
               (mapcar (lambda(x) "*")
                       (number-sequence 1
                                        (- (length (match-string 0))
                                           2)))))))))

Primero, untabifyla región antes de saltar a su inicio. Luego, mientras vemos espacios en blanco al comienzo de una línea, los reemplazamos con un comentario que es tan largo como dicho espacio en blanco. Para ser exactos, el comentario a insertar está construido por

 (format"/%s/"(apply'concat(mapcar(lambda(x)"*")(number-sequence 1(-(length(match-string 0))2)))))

que en sí ocupa 97 bytes. Una solución más corta para copiar algunas cadenas n veces es muy apreciada.


1

Ruby, 52 47 + 1 (bandera p) = 48 bytes

Editar : guardado 5 bytes completos, gracias a Value Ink

ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'

1
¿Puede usar la pbandera para aprovechar el hecho de que (g) sub modifica $_y por lo tanto cambia el valor impreso? ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
Value Ink

Gracias, no sabía que (g)subsin Bang puede modificar $_aquí.
michau

1

GNU sed, 66 64 + 1 (r flag) = 65 bytes

Editar: 1 byte menos gracias a la sugerencia de Riley .

s/\t/    /g
s,^ ( *) ,/\1\n,
:
s,^(/\**) ( *\n),\1*\2,
t
s,\n,/,

Ejecutar: sed -rf formatter.sed input_file

La razón para separarse con \nlos espacios iniciales del resto del texto en esa línea es porque, de lo contrario, una línea C ++ que comience con un comentario como este /* */se convertiría en /*****/una línea 4 más simple como s,^(/\**) ,\1*,o incluso s,^(/\**) ( */),\1*\2,. Dado que sed ejecuta el script para cada línea de entrada, no \nse introduce ningún en el espacio del patrón en la lectura.


Puede guardar un byte no colocando el cierre /hasta que reemplace el \n. Eso te ahorra tener que igualarlo en la línea 4.
Riley

@Riley Buena captura. Se actualizó el código.
seshoumara

Puede guardar otro reemplazando \tcon un carácter de tabulación.
Riley

@Riley Eso es cierto, pero como no se imprimirá como una pestaña aquí, tengo dudas. Lo tendré en cuenta para futuras respuestas sed con conteos de bytes más competitivos.
seshoumara
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.