Конец вкладки против космической войны


24

Конец вкладки против космической войны

Итак, было много споров о том, использовать ли табуляции или пробелы для отступа / форматирования кода. Можете ли вы помочь университету уладить спор, перейдя на невероятно сумасшедший уникальный метод форматирования.


Ваша задача - написать полную программу или функцию, которая расширяет все вкладки на четыре области. И затем заменяет серию из n ведущих пробелов на "/ (n - две звезды здесь) /". Вы получите ввод по нескольким строкам в любом приемлемом формате (однострочный массив строк для каждой новой строки. Массив столбцов и т. Д.)

Образец ввода бесстыдно украден . Обратите внимание, что поскольку в SE вкладки автоматически расширяются до четырех пробелов, я представляю их как символ «^», но вы также должны обрабатывать вкладки (кодовая точка 0x09). Все символы «^» представляют собой табуляцию.

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! 

Образец вывода

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! 

Поскольку университету требуется место для загрузки как Vim, так и Emacs, вам достаточно места для хранения вашего кода. Поэтому это и выигрывает самый короткий код. Вы можете предположить, что входные данные правильно сформированы и строки с менее чем четырьмя пробелами (после замены вкладок) могут привести к неопределенному поведению.

отказ

Эта «превосходная» стратегия форматирования была предоставлена ​​Geobits и воспроизводится с его разрешения. Никто из программистов не пострадал во время постановки этой задачи.


1
Будут ли вкладки появляться только в начале строк (т.е. как отступ)? Могут ли строки иметь смешанный отступ (табуляции + пробелы)?
Линн

20
Кто-то, пожалуйста, отправьте ответ, написанный в Whitespace .
GuitarPicker

2
Должны ли мы считать строки, начинающиеся с /*, или это можно считать не «правильно сформированным вводом»? Исходный файл C ++ был бы лучшим тестом, потому что его многострочный комментарий /* */мог бы разбить некоторые ответы, которые заменяют первый и последний из первых пробелов на «а» /, а затем переходить к заполнению пробелов *.
Сешумара

1
Война закончилась: medium.com/@hoffa/… (если, конечно, вы не программируете на C).
Стакан

1
@RohanJhunjhunwala Итак, теперь я снова задаю свой первый вопрос, поскольку речь шла не о компилируемом коде. Представьте тот же /* */код C ++, но на этот раз в начале строки. Согласно вашей спецификации его следует оставить как есть. Здесь есть ловушка, и она уже обнаружила неправильные ответы, что регулярное выражение, например, скажем, /\** /используемое, чтобы заполнить эти пробелы между // звездочками, превратило бы строку в /***/. Я также видел это преобразование /*//*/. Я предполагаю, что оба неверны.
seshoumara

Ответы:


2

V , 21 , 20 байтов

Íô/    
Î^hr/hv0r*r/

Попробуйте онлайн!

Это буквально прямой порт моего vim-ответа. Заметные различия:

  • Команда Í(Глобальная замена) автоматически заполняет /gфлаг, который сохраняет два байта

  • ô идентично \t

  • ÎЭто мнемоника для :%norm, и она также заполняет необходимое пространство между :%normнабором нажатий клавиш.

  • Задний возврат каретки в конце добавляется неявно.


27

Vim, 37, 34, 33, 32 байта

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

Попробуйте онлайн!

Обратите внимание, что для этого требуется возврат каретки (ввод) в vim, но не в онлайн-переводчике.

Это использует интерпретатор V, потому что он обратно совместим. Очень простое решение.

Вот рисунок, который позволяет увидеть решение в режиме реального времени. Здесь используется немного более старая версия, и я добавил несколько дополнительных нажатий клавиш, чтобы она работала медленнее, чтобы вы могли видеть, что происходит:

введите описание изображения здесь

И вот объяснение того, как это работает:

:%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

Я собирался +1 для использования, gно потом вы отредактировали, чтобы не использовать g: / +1 в любом случае: D
Downgoat

@ Downgoat Хаха, спасибо! На самом деле я гораздо больше горжусь этой версией, :gпотому что она использует менее известную функцию: normкоманда отменяется в случае ^F<space>неудачи. По :%norm ^F<space>fooсути, это то же самое, что и :g/^ /norm fooзабавные Vim-хаки. : D
DJMcMayhem

да, я думал, что ^ F был использован для размещения экрана. у него другое поведение внутри norm?
Вниз

1
@ Downgoat Ха-ха, нет, это ^Fне <C-f>обозначение ключа Silly Vim. В данном случае это ^переход к первому непробельному символу и F<space>поиск первого пробела за курсором.
DJMcMayhem

оооо, теперь это имеет гораздо больше смысла> _>
Downgoat

11

Perl, 41 байт

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

Запустите с -pфлагом, вот так:

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

Заменить на вкладку (в Bash попробуйте набрать Control-V Tab.)


1
Способ perlзаменил эту обратную ссылку на месте, я бы хотел, чтобы sedэто тоже было.
Сешумара

7

Чеддер , 60 57 56 байт

Сохранено 3 байта благодаря @Conor O'Brien

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

Я бы хотел, чтобы у Чеддера было лучшее форматирование строк.

Попробуйте онлайн!

объяснение

Это функция. @является функционализированным свойством представляет (например, ruby's &:), позволяя вам делать такие вещи, как: `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
 )

Если вы не знакомы с регулярным выражением:

/^ +/gm

это в основном соответствует одному или нескольким ( +) пробелам ( ) в начале ( ^) каждой ( g) строки ( m).


ли буквенные вкладки работают в регулярных выражениях чеддера? также /^ +/достаточно в качестве регулярного выражения, поскольку мы можем предположить, что начальные пробелы будут по крайней мере 4 в длину.
Конор О'Брайен

@ ConorO'Brien Я верю, что они делают, но я не проверял
Downgoat

Вкладки должны быть заменены до преобразования.
Конор О'Брайен

@ ConorO'Brien ой> _> У меня так было изначально, а потом я его поменял
Downgoat

6

Mathematica, 97 байт

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

Анонимная функция. Принимает строку в качестве ввода и возвращает строку в качестве вывода.


5

Python 3, 124 байта

Использует доброе старое регулярное выражение.

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

Идео это!


4

Java 210 207 байт

Это эталонное решение, которое реализует его наивно.

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

6
Vim: 37 байт, Cheddar: 65 байт, JavaScript: 75 байт, а затем Java на 210 байт: P, почему я не удивлен
Downgoat

1
Очень сжатый код в Java: P
Рохан Jhunjhunwala

Вы можете изменить последний для цикла , чтобы сохранить 1 байт: for(int j=0;++j<i-1;). Кроме того , вы можете удалить int до того j, и поместить его после уже присутствующему междунар:int i=s.length()-(x=s.replaceAll("^\\s+", "")).length(),j;
Кевин Cruijssen

это не может быть лямбда, чтобы побрить байты, используя (a) -> {...}?
bunyaCloven

По крайней мере, он по-прежнему читабелен и не нуждается в дальнейших комментариях: o)
Рене

3

JavaScript ES6, 75 байт

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

Замените \tна буквальную вкладку в вашем коде.


3

Ява, 185 184 167 152 байта

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

Учитывая очень слабое определение массива строк, данное в первоначальном посте, я использовал его, Stream<String>что позволяет сэкономить некоторые байты.

Я использовал другие методы, чем RI, чтобы достичь той же цели. Сам алгоритм скорее тот же.

Тестирование и ungolfed :

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

Сетчатка , 25 байт

Символ \tдолжен быть заменен реальным символом табуляции (0x09).

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

Попробуйте онлайн!

объяснение

\t
4$* 

Замените каждую вкладку четырьмя пробелами.

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

Transform каждой строки отдельно ( %) путем сопоставления 2+Nпробелов в начале строки и заменить его , /.../где ...это Nкопия *.



2

САС (56 + 1 для -r) 57

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

Где находится вкладка
1. заменяет вкладки пробелами.
2. заменяет первый и последний начальный пробел на /.
3. заменяет первый пробел после /и 0+ *s на, *пока не будет совпадения.


Поскольку указан sed, в коде не нужно использовать одинарные кавычки, также как и при удалении -r 'из других ответов sed, поскольку вы можете рассматривать сценарий как сохраненный в исходном файле, с которым вы работаете -f. Любые дополнительные флаги, используемые как n или r, должны учитываться как один байт каждый. Таким образом, здесь вы экономите 2 байта.
seshoumara

Я так и думал, но хочу точно. Спасибо.
Райли

Команда ;после t также не нужна. Что касается самого кода, вам нужен ^ в начале третьей sкоманды, в противном случае ввод, такой как «3/5», превращается в «3 / * 5». В первой sкоманде у вас есть вкладка, но она не отображается правильно и вводит в заблуждение, поэтому либо используйте \ t, либо укажите после, чтобы char был вкладкой.
Сешумара

@seshoumara Спасибо, я пытаюсь отправить сообщение с телефона ... Это не самая простая вещь.
Райли

Я думаю, что потратил больше времени на редактирование этого ответа, чем все остальные вместе взятые. Спасибо за помощь!
Райли

1

Университет должен рассмотреть возможность предоставления немного больше места для программ в Emacs Lisp (или по умолчанию tabifyи untabifyтолько), поскольку они становятся еще более многословными, чем Java. Следует также обратить пристальное внимание на учеников (или учителей), чей размер инактивации меньше четырех или которые случайно пишут на не-C-подобном языке.

Следующее решение имеет 206 байтов

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

Предполагая, что это tab-widthне должно быть явно установлено, мы можем сохранить 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))))))))

И негольфированная версия будет выглядеть так

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

Мы сначала untabifyрегион, прежде чем прыгать к его началу. Затем, пока мы видим пробел в начале строки, мы заменяем его комментарием, который равен указанному пробелу. Чтобы быть точным, комментарий для вставки построен

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

что само по себе занимает 97 байт. Более короткое решение для копирования строки n раз высоко ценится.


1

Ruby, 52 47 + 1 (флаг p) = 48 байт

Редактировать : сохранено целых 5 байтов, благодаря Value Ink

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

1
Можете ли вы использовать pфлаг, чтобы воспользоваться тем, что (g) sub изменяет $_и, таким образом, изменяет напечатанное значение? ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
Value Ink

Спасибо, я не знал, что (g)subбез взрыва можно изменить $_здесь.
Микау

1

GNU sed, 66 64 + 1 (флаг r) = 65 байт

Изменить: на 1 байт меньше по предложению Райли .

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

Запустите: sed -rf formatter.sed input_file

Причина разделения с \nведущими пробелами от остального текста в этой строке заключается в том, что в противном случае строка C ++, начинающаяся с комментария, подобного этому, /* */превратилась бы в /*****/более простую строку типа 4 s,^(/\**) ,\1*,или даже s,^(/\**) ( */),\1*\2,. Поскольку sed выполняет сценарий для каждой строки ввода, \nпри чтении в пространство шаблона не вводится no .


Вы можете сохранить байт, не вставляя закрытие, /пока не замените \n. Это избавит вас от необходимости сопоставлять его в строке 4.
Riley

@ Райли Хороший улов. Обновил код.
Сешумара

Вы можете сохранить другой, заменив \tсимвол табуляции.
Райли

@ Riley Это правда, но, поскольку здесь не будет печататься вкладка, я сомневаюсь. Я буду помнить это для будущих ответов sed с количеством байтов, более конкурентоспособным.
Сешумара
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.