Zakończ zakładki kontra wojna kosmiczna

24

Zakończ zakładki kontra wojna kosmiczna

Dyskutowano więc o tym, czy do wcięcia / formatowania kodu należy używać tabulatorów lub spacji. Czy możesz pomóc uniwersytetowi rozwiązać spór, przechodząc do niezwykle szalonej, unikalnej metody formatowania.


Twoim zadaniem jest napisanie pełnego programu lub funkcji, która rozłoży wszystkie tabulatory na cztery spacje. A następnie zamienia ciąg n wiodących spacji na „/ (n - dwie gwiazdki tutaj) /”. Otrzymasz dane wejściowe w wielu wierszach w dowolnym rozsądnym formacie (tablica pojedynczych ciągów dla każdej nowej linii. Tablica kolumnowa itp.)

Przykładowe dane bezwstydnie skradzione . Zwróć uwagę, że ponieważ tabulatory są automatycznie rozszerzane do czterech spacji w SE, reprezentuję je jako znak „^”, ale musisz również obsługiwać tabulatory (punkt kodowy 0x09). Wszystkie znaki „^” reprezentują tabelę.

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! 

Próbka wyjściowa

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! 

Ponieważ uniwersytet potrzebuje miejsca do pobrania zarówno Vima, jak i Emacsa, masz bardzo mało miejsca na swój kod. Dlatego jest to i wygrywa najkrótszy kod. Możesz założyć, że dane wejściowe są dobrze uformowane, a linie z mniej niż czterema spacjami (po zastąpieniu tabulatorami) mogą powodować niezdefiniowane zachowanie.

Zrzeczenie się

Ta „doskonała” strategia formatowania powstała dzięki uprzejmości Geobits i została odtworzona za jego zgodą. Podczas tworzenia tego wyzwania żaden programista nie został poszkodowany.

Rohan Jhunjhunwala
źródło
1
Czy tabulatory pojawią się tylko na początku linii (tj. Jako wcięcie)? Czy linie mogą mieć mieszane wcięcia (tabulatory + spacje)?
Lynn
20
Ktoś prześlij odpowiedź napisaną w białej spacji .
GuitarPicker,
2
Czy powinniśmy rozważyć linie zaczynające się od /*, czy też można to uznać za „dobrze sformułowany wkład”? Plik źródłowy C ++ byłby lepszym testem, ponieważ jego komentarz wielowierszowy /* */prawdopodobnie złamałby niektóre odpowiedzi, które zamieniają pierwsze i ostatnie z wiodących spacji na /, a następnie kontynuują wypełnianie spacjami *.
seshoumara,
1
Wojna się skończyła: medium.com/@hoffa/… (chyba że programujesz w C, najwyraźniej.)
zlewka
1
@RohanJhunjhunwala Więc teraz zadaję moje pierwsze pytanie, ponieważ nie chodziło o kompilowany kod. Wyobraź sobie ten sam /* */kod C ++, ale tym razem na początku wiersza. Zgodnie ze specyfikacją należy go pozostawić bez zmian. Tutaj pułapka jest, i już zauważyła błędne odpowiedzi, że wyrażenie regularne, takie jak powiedzmy /\** /użyte do wypełnienia tych spacji między // gwiazdkami, zamieniłoby linię /***/. Widziałem także tę konwersję /*//*/. Zakładam, że oba są nieprawidłowe.
seshoumara,

Odpowiedzi:

2

V , 21 , 20 bajtów

Íô/    
Î^hr/hv0r*r/

Wypróbuj online!

To dosłownie tylko bezpośredni port mojej odpowiedzi vima. Znaczące różnice:

  • ÍKomendy (Global substytut) automatycznie wypełnia /gflagą, co pozwala zaoszczędzić dwa bajty

  • ô jest identyczny z \t

  • ÎJest mnemonikiem dla :%norm, a także wypełnia niezbędną przestrzeń pomiędzy :%normi zestawem klawiszy.

  • Końcowy powrót karetki na końcu jest domyślnie dodawany.

DJMcMayhem
źródło
27

Vim, 37, 34, 33, 32 bajty

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

Wypróbuj online!

Zauważ, że wymaga to powrotu karetki (enter) w vimie, chociaż nie w tłumaczu online.

Używa interpretera V, ponieważ jest kompatybilny wstecz. Bardzo proste rozwiązanie.

Oto gif, który pozwala zobaczyć rozwiązanie w czasie rzeczywistym. Używa to nieco starszej wersji i dodałem kilka dodatkowych naciśnięć klawiszy, aby działał wolniej, dzięki czemu można zobaczyć, co się dzieje:

enter image description here

A oto wyjaśnienie, jak to działa:

:%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
źródło
Miałem +1 za używanie, gale potem edytowałeś, by nie używać g: / +1 w każdym razie: D
Downgoat
@downgoat Haha, dzięki! W rzeczywistości jestem o wiele bardziej dumna z wersji, :gponieważ nadużywa mniej znanej funkcji: normpolecenie zostanie anulowane, jeśli się ^F<space>nie powiedzie. Tak :%norm ^F<space>foojest w zasadzie to samo, co :g/^ /norm foociekawego Vima hacki. : D
DJMcMayhem
huh, myślałem, że ^ F został użyty do umieszczenia ekranu. czy ma w sobie inne zachowanie norm?
Downgoat
1
@downgoat Haha, nie ^F, nie <C-f>notacja klucza Silly Vim. W takim przypadku ^przeskocz do pierwszego nie-białego znaku, i F<space>Który znajduje pierwszą spację za kursorem.
DJMcMayhem
ohhh, to ma teraz o wiele więcej sensu> _>
Downgoat
11

Perl, 41 bajtów

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

Uruchom z -pflagą, tak:

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

Zastąp tabulatorem (w Bash spróbuj wpisać Control-V Tab).

Lynn
źródło
1
Sposób, w jaki perlzastąpiłem to odniesienie na miejscu, chciałbym, żeby sedto też było.
seshoumara
7

Cheddar , 60 57 56 bajtów

Zaoszczędź 3 bajty dzięki @Conor O'Brien

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

Chciałbym, żeby Cheddar miał lepsze formatowanie napisów.

Wypróbuj online!

Wyjaśnienie

To jest funkcja. @to reprezentuje funkcjonalizowaną właściwość (np. ruby &:) pozwalającą ci robić rzeczy takie jak: `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
 )

Jeśli nie znasz regex:

/^ +/gm

to w zasadzie dopasowało jedną lub więcej ( +) spacji ( ) na początku ( ^) każdej ( g) linii ( m).

Downgoat
źródło
czy dosłowne tabulatory działają w wyrażeniach regularnych cheddar? /^ +/wystarcza również jako wyrażenie regularne, ponieważ możemy założyć, że spacje wiodące będą miały co najmniej 4 długości.
Conor O'Brien
@ ConorO'Brien Wydaje mi się, że tak, ale nie testowałem
Downgoat
Zakładki powinny zostać zastąpione przed transformacją.
Conor O'Brien
@ ConorO'Brien oh> _> Pierwotnie miałem to w ten sposób, a potem to zmieniłem
Downgoat
6

Mathematica, 97 bajtów

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

Funkcja anonimowa. Pobiera ciąg jako dane wejściowe i zwraca ciąg jako dane wyjściowe.

LegionMammal978
źródło
5

Python 3, 124 bajty

Używa dobrego wyrażenia regularnego.

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 to!

Rozpad beta
źródło
4

Java 210 207 bajtów

Jest to rozwiązanie referencyjne, które implementuje je naiwnie.

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
źródło
6
Vim: 37 bajtów, Cheddar: 65 bajtów, JavaScript: 75 bajtów, potem jest Java w 210 bajtach: P dlaczego nie jestem zaskoczony
Downgoat
1
Bardzo zwięzły kod w java: P
Rohan Jhunjhunwala
Można zmienić ostatniej pętli for, aby zapisać 1 bajt: for(int j=0;++j<i-1;). Możesz także usunąć int poprzedni ji umieścić go po już istniejącym int:int i=s.length()-(x=s.replaceAll("^\\s+", "")).length(),j;
Kevin Cruijssen
czy to nie może być lambda do golenia bajtów za pomocą (a) -> {...}?
bunyaCloven
Przynajmniej jest nadal czytelny i nie wymaga dalszych komentarzy: o)
René
3

JavaScript ES6, 75 bajtów

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

Zamień \tna literalną kartę w kodzie.

Conor O'Brien
źródło
3

Java, 185 184 167 152 bajtów

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

Biorąc pod uwagę bardzo luźną definicję tablicy ciągów podaną w początkowym poście, użyłem jej, Stream<String>co pozwala na pewne konsekwentne oszczędności bajtów.

Użyłem innych technik niż RI, aby osiągnąć ten sam cel. Sam algorytm jest raczej taki sam.

Testowanie i niestosowanie :

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
źródło
2

Siatkówka , 25 bajtów

\tNależy zastąpić rzeczywistej znak tabulatora (0x09).

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

Wypróbuj online!

Wyjaśnienie

\t
4$* 

Zastąp każdą kartę czterema spacjami.

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

Przekształcanie każdej linii oddzielnie ( %) dopasowując 2+Nprzestrzenie na początku linii, a zastąpienie go /.../w którym ...to Nkopie *.

Martin Ender
źródło
2

Python, 125 111 bajtów

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

atlasolog
źródło
2

SED (56 + 1 dla -r) 57

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

Gdzie jest karta
1. zastępuje karty spacjami.
2. zastępuje pierwszą i ostatnią wiodącą spację /.
3. zastępuje pierwsze spację po /i 0+ *s, *dopóki nie będzie dopasowania.

Riley
źródło
Ponieważ podano sed, wokół kodu nie są potrzebne pojedyncze cudzysłowy, podobnie jak usunięcie -r '' z innych odpowiedzi sed, ponieważ można uznać skrypt za przechowywany w pliku źródłowym, z którym się uruchamiasz -f. Wszelkie dodatkowe flagi, takie jak n lub r, powinny być liczone jako jeden bajt. W ten sposób oszczędzasz 2 bajty.
seshoumara,
Tak myślałem, ale chcę mieć pewność. Dzięki.
Riley,
Polecenie ;po t także nie jest konieczne. Jeśli chodzi o sam kod, potrzebujesz ^ na początku trzeciego spolecenia, w przeciwnym razie dane takie jak „3/5” zamieniane są na „3 / * 5”. W pierwszym spoleceniu faktycznie masz tam kartę, ale nie jest ona poprawnie wyświetlana i wprowadza w błąd, więc użyj \ t lub określ po tym, że znak był kartą.
seshoumara
@seshoumara Dzięki, próbuję pisać z mojego telefonu ... To nie jest najłatwiejsze.
Riley,
Wydaje mi się, że spędziłem więcej czasu na edytowaniu tej odpowiedzi niż na wszystkich innych razem. Dzięki za pomoc!
Riley,
1

Uniwersytet powinien rozważyć umożliwienie nieco więcej miejsca na programy w Emacs Lisp (lub domyślnie tabifyi untabifysamodzielnie), ponieważ stają się one bardziej gadatliwe niż Java. Powinien także zwracać szczególną uwagę na uczniów (lub nauczycieli), których rozmiar identyfikacyjny jest mniejszy niż czterech lub którzy akurat kodują w języku innym niż C.

Poniższe rozwiązanie ma 206 bajtów

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

Zakładając, że tab-widthnie trzeba tego wyraźnie ustawiać, możemy zapisać 20 z nich.

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

Wersja bez golfa wyglądałaby tak

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

Najpierw untabifyregion, zanim przejdziemy do jego początku. Następnie, gdy widzimy białe znaki na początku wiersza, zastępujemy je komentarzem, który jest tak długi jak wspomniane białe znaki. Mówiąc ściślej, komentarz do wstawienia jest konstruowany przez

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

który sam zajmuje 97 bajtów. Bardzo cenione jest krótsze rozwiązanie do skopiowania niektórych ciągów n razy.

Lord Yuuma
źródło
1

Rubin, 52 47 + 1 (flaga p) = 48 bajtów

Edycja : zapisano całe 5 bajtów dzięki funkcji Value Ink

ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
Michau
źródło
1
Czy możesz użyć pflagi, aby skorzystać z faktu, że (g) sub modyfikuje, $_a tym samym zmienia drukowaną wartość? ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
Wartość tuszu
Dzięki, nie wiedziałem, że (g)subBang nie może $_tutaj zmodyfikować .
michau,
1

GNU sed, 66 64 + 1 (flaga r) = 65 bajtów

Edycja: 1 bajt mniej dzięki sugestii Riley .

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

Uruchom: sed -rf formatter.sed plik_wejściowy

Powodem oddzielenia się \nwiodącymi spacjami od reszty tekstu w tym wierszu jest to, że w przeciwnym razie wiersz C ++ rozpoczynający się od takiego komentarza /* */zostałby przekształcony w /*****/prostszą linię 4 podobną s,^(/\**) ,\1*,lub nawets,^(/\**) ( */),\1*\2, . Ponieważ sed wykonuje skrypt dla każdej linii wejściowej, \npodczas odczytu nie jest wprowadzane żadne miejsce w obszarze wzorców.

seshoumara
źródło
Możesz zapisać bajt, nie wkładając zamknięcia, /dopóki nie zastąpisz \n. Dzięki temu nie musisz dopasowywać go w linii 4.
Riley
@Riley Good catch. Zaktualizowałem kod.
seshoumara,
Możesz zapisać kolejny, zastępując \tznakiem tabulacji.
Riley,
@ Riley To prawda, ale ponieważ nie zostanie tu wydrukowana jako zakładka, mam wątpliwości. Będę o tym pamiętać w przypadku przyszłych odpowiedzi sed z liczbą bajtów bardziej konkurencyjną.
seshoumara,