Mettre fin aux onglets contre la guerre spatiale

24

Mettre fin aux onglets contre la guerre spatiale

Ainsi, il y a eu beaucoup de débats sur l'opportunité d'utiliser des tabulations ou des espaces pour indenter / formater le code. Pouvez-vous aider l'université à régler le différend en adoptant une méthode de mise en forme unique et incroyablement folle ?


Votre travail consiste à écrire un programme ou une fonction complète qui étend tous les onglets en quatre espaces. Et puis remplace une série de n espaces de tête par "/ (n - deux étoiles ici) /". Vous recevrez une entrée sur plusieurs lignes dans n'importe quel format raisonnable (un seul tableau de chaînes de chaînes pour chaque nouvelle ligne. Tableau en colonnes, etc.)

Exemple d'entrée volée sans vergogne . Notez que puisque les tabulations sont étendues automatiquement à quatre espaces sur SE, je le représente comme le caractère "^", mais vous devez également gérer les tabulations (codepoint 0x09). Tous les caractères "^" représentent une tabulation.

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! 

Exemple de sortie

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! 

Parce que l'université a besoin d'espace pour télécharger à la fois Vim et Emacs, vous avez très peu de stockage pour votre code. C'est donc le et le code le plus court l'emporte. Vous pouvez supposer que l'entrée est bien formée et que les lignes avec moins de quatre espaces (après le remplacement des tabulations) peuvent entraîner un comportement non défini.

Avertissement

Cette "excellente" stratégie de formatage est une gracieuseté de Geobits et est reproduite avec sa permission. Aucun programmeur n'a été blessé lors de la production de ce défi.

Rohan Jhunjhunwala
la source
1
Les tabulations n'apparaîtront-elles qu'au début des lignes (c'est-à-dire comme indentation)? Les lignes peuvent-elles avoir une indentation mixte (tabulations + espaces)?
Lynn
20
Quelqu'un veuillez soumettre une réponse écrite en blanc .
GuitarPicker
2
Faut-il considérer les lignes commençant par /*, ou peut-on supposer que ce n'est pas une «entrée bien formée»? Un fichier source C ++ aurait été un meilleur test, car son commentaire multiligne /* */pourrait éventuellement casser certaines réponses qui remplacent le premier et le dernier des espaces de tête par un /, puis continuer à remplir les espaces avec *.
seshoumara
1
La guerre est terminée: medium.com/@hoffa/… (sauf si vous programmez en C, apparemment.)
bécher
1
@RohanJhunjhunwala Alors maintenant, je pose à nouveau ma première question, car il ne s'agissait pas de code compilable. Imaginez le même /* */code C ++, mais cette fois au début de la ligne. Selon vos spécifications, il doit être laissé tel quel. Ici, le piège est, et a déjà repéré de mauvaises réponses, qu'un regex comme disons /\** /utilisé pour remplir ces espaces entre // avec des astérisques transformerait la ligne en /***/. J'ai également vu cette conversion /*//*/. Je suppose que les deux sont incorrects.
seshoumara

Réponses:

2

V , 21 , 20 octets

Íô/    
Î^hr/hv0r*r/

Essayez-le en ligne!

C'est littéralement juste un port direct de ma réponse vim. Les différences notables:

  • La Ícommande (substitut global) remplit automatiquement l' /gindicateur, ce qui économise deux octets

  • ô est identique à \t

  • ÎEst un mnémonique pour :%norm, et il remplit également l'espace nécessaire entre :%normet l'ensemble des frappes.

  • Le retour chariot fin à la fin est implicitement ajouté.

DJMcMayhem
la source
27

Vim, 37, 34, 33, 32 octets

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

Essayez-le en ligne!

Notez que cela nécessite un retour chariot fin (entrée) dans vim, mais pas dans l'interpréteur en ligne.

Cela utilise l'interpréteur V car il est rétrocompatible. Une solution très simple.

Voici un gif qui vous permet de voir la solution se produire en temps réel. Cela utilise une version légèrement plus ancienne, et j'ai ajouté quelques touches supplémentaires pour le ralentir afin que vous puissiez voir ce qui se passe:

entrez la description de l'image ici

Et voici l'explication de son fonctionnement:

:%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
DJMcMayhem
la source
J'allais +1 pour l'utilisation, gmais vous avez modifié pour ne pas utiliser g: / +1 de toute façon: D
Downgoat
@downgoat Haha, merci! Je suis en fait beaucoup plus fier de la version sans :gcar elle abuse d'une fonctionnalité moins connue: la normcommande est annulée en cas d' ^F<space>échec. C'est donc :%norm ^F<space>fooessentiellement la même chose que :g/^ /norm fooles hacks amusants de Vim. : D
DJMcMayhem
hein, je pensais que ^ F était utilisé pour positionner l'écran. a-t-il un comportement différent à l'intérieur norm?
Downgoat
1
@downgoat Haha, non c'est ^Fpas la <C-f>notation de clé Silly Vim. Dans ce cas, il s'agit de ^passer au premier caractère non blanc et de F<space>trouver le premier espace derrière le curseur.
DJMcMayhem
ohhh, ça a tellement plus de sens maintenant> _>
Downgoat
11

Perl, 41 octets

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

Courez avec le -pdrapeau, comme ceci:

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

Remplacez par un onglet (dans Bash, essayez de taper Control-V Tab.)

Lynn
la source
1
La façon dont a perlremplacé cette référence sur place, je souhaite sedque cela aussi.
seshoumara
7

Cheddar , 60 57 56 octets

Enregistré 3 octets grâce à @Conor O'Brien

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

Je souhaite que Cheddar ait un meilleur formatage des chaînes.

Essayez-le en ligne!

Explication

Ceci est une fonction. @est une propriété représentée (par exemple ruby &:) vous permettant de faire des choses comme: `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 vous n'êtes pas familier avec l'expression régulière:

/^ +/gm

cela correspondait essentiellement à un ou plusieurs ( +) espaces ( ) au début ( ^) de chaque ( g) ligne ( m).

Downgoat
la source
les onglets littéraux fonctionnent-ils dans les expressions rationnelles du cheddar? aussi, /^ +/suffit comme expression régulière, car nous pouvons supposer que les espaces de tête auront au moins 4 longueurs.
Conor O'Brien
@ ConorO'Brien Je crois que oui mais je n'ai pas testé
Downgoat
Les onglets sont censés être remplacés avant la transformation.
Conor O'Brien
@ ConorO'Brien oh> _> Je l'avais comme ça à l'origine, puis je l'ai changé
Downgoat
6

Mathematica, 97 octets

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

Fonction anonyme. Prend une chaîne en entrée et renvoie une chaîne en sortie.

LegionMammal978
la source
5

Python 3, 124 octets

Utilise un bon vieux regex.

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!

Beta Decay
la source
4

Java 210 207 octets

C'est la solution de référence qui la met en œuvre naïvement.

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);}}
Rohan Jhunjhunwala
la source
6
Vim: 37 octets, Cheddar: 65 octets, JavaScript: 75 octets, puis il y a Java à 210 octets: P pourquoi je ne suis pas surpris
Downgoat
1
Code très concis en java: P
Rohan Jhunjhunwala
Vous pouvez changer la dernière boucle pour sauver 1 octet: for(int j=0;++j<i-1;). En outre, vous pouvez supprimer l' int avant jet le mettre après l'int. Déjà présent:int i=s.length()-(x=s.replaceAll("^\\s+", "")).length(),j;
Kevin Cruijssen
ne peut-il pas être un lambda de raser des octets en utilisant (a) -> {...}?
bunyaCloven
Au moins, il est toujours lisible et n'a pas besoin d'autres commentaires: o)
René
3

JavaScript ES6, 75 octets

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

Remplacez \tpar un onglet littéral dans votre code.

Conor O'Brien
la source
3

Java, 185 184 167 152 octets

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;})

Étant donné la définition très vague du tableau de chaînes donnée dans le post initial, j'ai utilisé Stream<String>ce qui permet des économies d'octets conséquentes.

J'ai utilisé des techniques différentes de celles du RI pour atteindre le même objectif. L'algorithme lui-même est plutôt le même.

Test et non 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);


  }
}
Olivier Grégoire
la source
2

Rétine , 25 octets

Le \tdoit être remplacé par un caractère de tabulation réel (0x09).

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

Essayez-le en ligne!

Explication

\t
4$* 

Remplacez chaque onglet par quatre espaces.

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

Transformez chaque ligne séparément ( %) en faisant correspondre les 2+Nespaces au début de la ligne et en la remplaçant par /.../...se trouvent des Ncopies de *.

Martin Ender
la source
2

Python, 125 111 octets

lambda s:'\n'.join(('/'+(len(L.replace('\t',' '*4))-len(L.strip())-2)*'*'+'/'+L.strip(),L)[L[0]>' ']for L in s)

https://repl.it/DGyh/2

atlasologue
la source
2

SED (56 + 1 pour -r) 57

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

Où se trouve un onglet
1. remplace les onglets par des espaces.
2. remplace le premier et le dernier espace de début par /.
3. remplace le premier espace après /et 0+ *par un *jusqu'à ce qu'il n'y ait pas de correspondance.

Riley
la source
Puisque sed est spécifié, aucun guillemet simple n'est nécessaire autour du code, de même que la suppression de -r '' de vos autres réponses sed, car vous pouvez considérer le script comme étant stocké dans un fichier source avec lequel vous exécutez -f. Tous les drapeaux supplémentaires utilisés comme n ou r doivent être comptés comme un octet chacun. Ainsi ici, vous économisez 2 octets.
seshoumara
C'est ce que je pensais, mais je veux sûr. Merci.
Riley
L' ;après la commande t n'est pas non plus nécessaire. Quant au code lui-même, vous avez besoin d'un ^ au début de la troisième scommande, sinon une entrée comme celle-ci "3/5" est transformée en "3 / * 5". Dans la première scommande, vous avez en fait un onglet, mais il n'est pas correctement affiché et trompeur, alors utilisez \ t ou spécifiez après, que char était un onglet.
seshoumara
@seshoumara Merci, j'essaie de poster depuis mon téléphone ... Ce n'est pas la chose la plus simple à faire.
Riley
Je pense que j'ai passé plus de temps à éditer cette réponse que toutes les autres combinées. Merci pour l'aide!
Riley
1

L'université devrait envisager d'accorder un peu plus d'espace aux programmes dans Emacs Lisp (ou par défaut à tabifyet untabifyseul), car ils sont encore plus verbeux que Java. Il devrait également prêter une attention particulière aux élèves (ou enseignants) dont la taille d'identification est inférieure à quatre ou qui se trouvent coder dans un langage non similaire à C.

La solution suivante a 206 octets

(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)))))))))

En supposant que cela tab-widthne doive pas être défini explicitement, nous pouvons en enregistrer 20.

(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))))))))

Et la version non golfée ressemblerait à ceci

(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)))))))))

Nous avons d'abord untabifyla région avant de sauter à son début. Ensuite, pendant que nous voyons un espace au début d'une ligne, nous le remplaçons par un commentaire qui est aussi long que ledit espace. Pour être exact, le commentaire à insérer est construit par

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

qui lui-même prend 97 octets. Une solution plus courte pour copier certaines chaînes n fois est très appréciée.

Lord Yuuma
la source
1

Rubis, 52 47 + 1 (indicateur p) = 48 octets

Edit : 5 octets entiers enregistrés, grâce à Value Ink

ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
michau
la source
1
Pouvez-vous utiliser le pdrapeau pour profiter du fait que (g) sub modifie $_et change ainsi la valeur imprimée? ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
Value Ink
Merci, je ne savais pas (g)subsans bang peut modifier $_ici.
michau
1

GNU sed, 66 64 + 1 (drapeau r) = 65 octets

Edit: 1 octet de moins grâce à la suggestion de Riley .

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

Exécutez: sed -rf formatter.sed input_file

La raison de la séparation avec un \ndes espaces de tête du reste du texte sur cette ligne, est parce que sinon une ligne C ++ commençant par un commentaire comme celui- /* */ci serait transformée en /*****/une ligne plus simple 4 comme s,^(/\**) ,\1*,ou même s,^(/\**) ( */),\1*\2,. Puisque sed exécute le script pour chaque ligne d'entrée, no \nest introduit dans l'espace modèle lors de la lecture.

seshoumara
la source
Vous pouvez enregistrer un octet en ne mettant pas la fermeture /avant d'avoir remplacé le \n. Cela vous évite d'avoir à le faire correspondre dans la ligne 4.
Riley
@Riley Bonne prise. Mise à jour du code.
seshoumara
Vous pouvez en enregistrer un autre en le remplaçant \tpar un caractère de tabulation.
Riley
@Riley C'est vrai, mais comme il ne sera pas imprimé sous forme d'onglet ici, je doute. Je garderai cela à l'esprit pour les futures réponses sed avec un nombre d'octets plus compétitif.
seshoumara