Сделать отступ строки, используя заданные скобки

16

Дан следующий вклад в программу:

  1. Список начальных символов блока
  2. Список символов конца блока
  3. Строка для форматирования

отформатируйте строку с блоками, разделенными двумя наборами символов с отступом.

Форматирование выполняется с двумя пробелами на уровень, а круглые скобки размещаются, как показано в примере ниже. Вы можете считать, что наборы открывающих и закрывающих символов не пересекаются.

Например, для {[(<и }])>в качестве открывающих и закрывающих наборов символов и следующей строки:

abc{xyz{text[note{comment(t{ex}t)abc}]}}

ожидается следующий вывод:

abc
{
  xyz
  {
    text
    [
      note
      {
        comment
        (
          t
          {
            ex
          }
          t
        )
        abc
      }
    ]
  }
}

Вы не можете жестко закодировать список символов «круглых скобок». Способ ввода не указан, однако; это могут быть аргументы командной строки или стандартный ввод, как вы пожелаете.

Прашант Бхате
источник
5
Можем ли мы предположить, что для каждой круглой скобки есть закрывающая и в том же порядке?
Хуан
Должна ли программа поддерживать какие-либо символы в скобках, указанные в качестве аргументов? например ./program 'p' 'q' <<< '1p23p45q67q8' или нужна только поддержка {[(<и }])>?
Джои Адамс
@ Джои, я бы предположил, что нет, хотя это было бы еще более впечатляюще.
Нил
joey: входные данные 1. символы открытых скобок 2. символы круглых скобок 3. строка для отступа. Хуан: мы можем предположить, что, хотя код не должен полагаться на это, я имею в виду, что delim является частью открывающей скобки, увеличивает отступ, иначе, если часть закрывающей скобки уменьшает отступ.
Прашант Бхате
1
@Phrasant Bhate: а в выходной?
Lowjacker

Ответы:

6

Рубин, 106 101 96 95

s,e,i=$*
i.scan(/[#{z=Regexp.quote s+e}]|[^#{z}]*/){|l|puts'  '*(s[l]?~-$.+=1:e[l]?$.-=1:$.)+l}

Ввод осуществляется через командную строку.

Lowjacker
источник
1
Вы можете сохранить 4 символа, используя ~-j+=1вместо (j+=1;j-1). Кроме того, использование $.везде вместо jпозволяет удалить j=0, что сохраняет другого персонажа.
Вентеро
6

Perl - 131 96 94 символов

$i="";for$_(split/([\Q$ARGV[0]$ARGV[1]\E])/,$ARGV[2]){$i=~s/..// if/[\Q$ARGV[1]\E]/;print "$i$_\n"if$_;$i.='  'if/[\Q$ARGV[0]\E]/;}

Похоже, должно быть место для устранения общих выражений, по крайней мере, но это быстрый способ, который обрабатывает пример, а также гипотезу Джои Адамса о произвольных скобках.


Действительно, было много возможностей для улучшения:

$_=pop;($s,$e)=map"[\Q$_\E]",@ARGV;for(split/($s|$e)/){print"  "x($i-=/$e/),"$_\n"if$_;$i+=/$s/}

... и еще немного:

$_=pop;($s,$e)=map"[\Q$_\E]",@ARGV;map{print"  "x($i-=/$e/),"$_\n"if$_;$i+=/$s/}split/($s|$e)/
DCharness
источник
3

Mathematica (не код гольф)

indent[str_String]:=Module[{ind,indent,f},
ind=0;
indent[i_]:="\n"<>Nest["    "<>ToString[#]&,"",i];
f[c_] :=  (indent[ind] <> c <> indent[++ind]) /; StringMatchQ["[({",___~~c~~___];
f[c_] := ( indent[--ind] <> c <>indent[ind])  /; StringMatchQ["])}",___~~c~~___];
f[c_] := (c <>indent[ind])       /; StringMatchQ[";,",___~~c~~___];
f[c_] := c  ;
f /@ Characters@ str//StringJoin
]

Тестовое задание

indent["abc{xyz{text[note{comment(t{ex}t)abc}]}}"]
abc
{
    xyz
    {
        text
        [
            note
            {
                comment
                (
                    t
                    {
                        ex
                    }
                    t
                )
                abc
            }

        ]

    }

}

В качестве бонуса можно использовать следующую функцию для форматирования выражения mathematica.

format[expr_] := indent[expr // FullForm // ToString]

РЕДАКТИРОВАТЬ (без кода гольф) Обновлен с тонким гранулярным контролем над способом перевода строк

indent[str_String, ob_String, cb_String, delim_String] := 
  Module[{ind, indent, f, tab}, ind = 0; tab = "    ";
   indent[i_, tab_, nl_] := nl <> Nest[tab <> ToString[#] &, "", i];
   f[c_] := (indent[ind, "", " "] <> c <> indent[++ind, tab, "\n"]) /;StringMatchQ[ob, ___ ~~ c ~~ ___];
   f[c_] := (indent[--ind, "", " "] <> c <> indent[ind, tab, "\n"]) /;StringMatchQ[cb, ___ ~~ c ~~ ___];
   f[c_] := (c <> indent[ind, tab, "\n"]) /;StringMatchQ[delim, ___ ~~ c ~~ ___];
   f[c_] := c;
   f /@ Characters@str // StringJoin];
format[expr_] := indent[expr // InputForm // ToString, "[({", "])}", ";"];

format[Hold@Module[{ind, indent, f, tab}, ind = 0; tab = "    ";
 indent[i_, tab_, nl_] := nl <> Nest[tab <> ToString[#] &, "", i];
 f[c_] := (indent[ind, "", " "] <> c <> indent[++ind, tab, "\n"]) /;StringMatchQ[ob, ___ ~~ c ~~ ___];
 f[c_] := (indent[--ind, "", " "] <> c <> indent[ind, tab, "\n"]) /;StringMatchQ[cb, ___ ~~ c ~~ ___];
 f[c_] := (c <> indent[ind, tab, "\n"]) /;StringMatchQ[delim, ___ ~~ c ~~ ___];
 f[c_] := c;
 f /@ Characters@str // StringJoin]]

Выход

Hold [
    Module [
         {
            ind, indent, f, tab }
        , ind = 0;
         tab = "    ";
         indent [
            i_, tab_, nl_ ]
         := StringJoin [
            nl, Nest [
                StringJoin [
                    tab, ToString [
                        #1 ]
                     ]
                 & , "", i ]
             ]
        ;
         f [
            c_ ]
         := StringJoin [
            indent [
                ind, "", " " ]
            , c, indent [
                ++ind, tab, "\n" ]
             ]
         /;
         StringMatchQ [
            ob, ___~~c~~___ ]
        ;
         f [
            c_ ]
         := StringJoin [
            indent [
                --ind, "", " " ]
            , c, indent [
                ind, tab, "\n" ]
             ]
         /;
         StringMatchQ [
            cb, ___~~c~~___ ]
        ;
         f [
            c_ ]
         := StringJoin [
            c, indent [
                ind, tab, "\n" ]
             ]
         /;
         StringMatchQ [
            delim, ___~~c~~___ ]
        ;
         f [
            c_ ]
         := c;
         StringJoin [
            f / @
                 Characters [
                    str ]
                 ]
             ]
         ]
Прашант Бхате
источник
Это вряд ли код гольф, с многосимвольными именами, как indent. Ваша цель - максимально краткий код или читабельность? Есть несколько способов сделать этот код короче, если это действительно ваша цель. Также: «Вы не можете жестко закодировать список символов в скобках». но разве это не то, что вы сделали здесь? Во всяком случае, извините, чтобы звучать так негативно; это просто кажется мне странным ответом на ваш собственный вызов.
Mr.Wizard
1
@ Mr.Wizard это не код гольф, я добавил его для собственной справки [обновлено, чтобы было понятно]. Я часто использую его, чтобы понять неформатированный код mathematica, размер которого превышает страницу
Prashant Bhate,
3

JavaScript, 255 227 205 символов

Эй, его длина идеально вписывается в байт! : D

function(s,e,t){R=eval.bind(0,"Array(n).join(' ')");for(i=n=0,b=r='';c=t[i++];)~s.indexOf(c)?(r+=b,b='\n'+R(++n)+c+'\n '+R(++n)):~e.indexOf(c)?b+='\n'+((n-=2)?R()+' ':'')+c+'\n'+(n?R()+' ':''):b+=c;return r+b}

Это функция, передайте ей начальные символы, конечные символы, а затем текст.

Рыбаковым
источник
Ваш собственный комментарий редактирования был использован против вас. : D
дверная ручка
@ Doorknob: я ... я думал, что никогда не делал этого. D: Мне очень жаль. (Вы охотились?)
Ry-
@ Doorknob: И спасибо, что напомнили мне об этом; сокращен :)
Ry-
Нет, я не охотился, просто наткнулся на этот вопрос, но я решил, и я нашел это : O: P
Ручка двери
2

Питон - 162 символа

i=f=0
s=""
l,r,z=[raw_input()for c in'   ']
o=lambda:s+("\n"+"  "*i)*f+c
for c in z:
 if c in l:f=1;s=o();i+=1
 elif c in r:i-=1;f=1;s=o()
 else:s=o();f=0
print s
Juan
источник
Обратите внимание, что задача требует, чтобы два набора скобок были частью ввода, а не были жестко закодированы.
Джои
@ Джои заметил, что я скоро исправлю это. Спасибо
Хуан
2

Python 2.7.X - 136 символов

import sys
a,c=sys.argv,0
for i in a[3]:
 if not(i in a[2]):print ' '*c+i
 else:print ' '*(c-4)+i
 if i in a[1]:c+=4
 if i in a[2]:c-=4

Использование : $ ./foo.py '(' ')' '(ab (cd (ef) gh) ij)'

Результирующий вывод:

(
    a
    b
    (
        c
        d
        (
            e
            f
        )
        g
        h
    )
    i
    j
)
arrdem
источник
Вам нужны пробелы после printутверждений?
Захари
2

С - 213 209

Я ненавижу глупые ошибки ...>. <

#include<stdio.h>
#include<string.h>
int main(int i,char**s){for(char q,r,c,t,a=0;~(c=getchar());t=q|r){q=!!strchr(s[1],c);a-=r=!!strchr(s[2],c);for(i=0;t|q|r&&i<2*a+1;putchar(i++?' ':'\n'));a+=q;putchar(c);}}

Считывает левую часть из первого аргумента командной строки, правую часть из второго аргумента и вводит отступ в stdin.

Довольно напечатано и прокомментировано:

int main(int i, char **s) {
  for (char q, r, /* is left-paren? is right-paren? */
            c,    /* character read from input */
            t,    /* last char was a paren-char */
            a=0;  /* indentation */
       ~(c = getchar());
       t = q|r) {
         q = !!strchr(s[1],c);
    a -= r = !!strchr(s[2],c);
    for (i=0; t|q|r && i<2*a+1; putchar(i++? ' ' : '\n'));
    a += q;
    putchar(c);
  }
}
Светляк
источник
1

С ( 159 225 символов)

#define q(s,c)strchr(s,c)
#define p(i,j,k)printf("\n%*s%c%c%*s",i,"",*s,k,j,"")
g(char*b,char*e,char*s){int i;for(i=0;*s;s++)q(b,*s)?p(i-2,i+=2,'\n'):q(e,*s)?q(b,*(s+1))||q(e,*(s+1))?p(i-=2,i-2,0):p(i-=2,i-2,'\n'):putchar(*s);}

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

#define p(i,j)printf("\n%*s%c\n%*s",i,"",*s,j,"")
f(char*b,char*e,char*s){int i;for(i=0;*s;s++){strchr(b,*s)?p(i-2,i+=2):strchr(e,*s)?p(i-=2,i-2):putchar(*s);}}

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

char * b - набор открывающих скобок, char * e - набор закрывающих скобок, а char * s - строка ввода.

Гарри К.
источник
1

Perl - 69 байт

TMTOWTDI делает код простым

#!perl -p
s/([[{(<])|([]})>])|\w+/"  "x($1?$t++:$2?--$t:$t)."$&
"/ge
Ходжунг Юн
источник
3
Вы должны взять скобки в качестве ввода, а не жестко их кодировать.
Гарет
1

Скала (2,9), 211 символов

object P extends App{def x(j:Int)={"\n"+"  "*j}
var(i,n)=(0,"")
for(c<-args(2)){if(args(0).exists(_==c)){print(x(i)+c)
i+=1
n=x(i)}else{if(args(1).exists(_==c)){i-=1
print(x(i)+c)
n=x(i)}else{print(n+c)
n=""}}}}
Gareth
источник
1

Perl - 89 85 байт

Версия ответа Hojung Youn, которая принимает символы блока через два аргумента.

#!perl -p
BEGIN{$b=pop;$a=pop}s/([$a])|([$b])|\w+/"  "x($1?$t++:$2?--$t:$t)."$&
"/ge

Называется как:

perl golf.pl<<<'abc{xyz{text[note{comment(t{ex}t)abc}]}}' '[{(<' ']})>'
Sorpigal
источник
Очень хорошая концепция, @Hojung и Sorpigal. Хотя это немного хрупко. Например, поменяйте местами] и} в аргументе close-paren, а] закрывает класс символов, что приведет к непревзойденной ошибке paren. Точно так же предположим, что открытый набор начинается с ^, возможно, чтобы соответствовать v в близком наборе; вы получите дополнение к предполагаемому классу [$ a]. Вот почему я использовал \ Q ... \ E в своем ответе. \ W + для непаренных символов работает для примера, но как насчет ввода типа 'x (foo-bar) y' '(' ')'? Конечно, не ясно, что код должен обрабатывать что-то подобное.
DCharness
1

Python3, 184 182 символа

import sys
_,p,q,t=sys.argv
i,f,x=0,1,print
for e in t:
 if e in p:f or x();x(' '*i+e);i+=2;f=1
 elif e in q:f or x();i-=2;f=1;x(' '*i+e)
 else:not f or x(' '*i,end='');f=x(e,end='')

Пример:

$ python3 ./a.py '{[(<' '}])>' 'abc{xyz{text[note{comment(t{ex}t)abc}]}}'
abc
{
  xyz
  {
    text
    [
      note
      {
        comment
        (
          t
          {
            ex
          }
          t
        )
        abc
      }
    ]
  }
}
Александр
источник
heinrich5991 предложил сохранить два символа, изменив вторую строку на_,p,q,t=sys.argv
Питер Тейлор
1

Groovy, 125

p=args;i=0;s={a,b->"\n"+"\t"*(b?i++:--i)+a+"\n"+"\t"*i};p[0].each{c->print p[1].contains(c)?s(c,1):p[2].contains(c)?s(c,0):c}

Вы можете сохранить скрипт в файле indent.groovy и попробовать его с помощью:
groovy indent.groovy "abc {xyz {text [note {comment (t {ex} t) abc}]}}" "{[(" ") ]}»

Марко Мартинелли
источник
Я пробовал в Groovy в течение часа, прежде чем увидел ваш ответ, я использовал аналогичный подход, но мой намного длиннее, чем ваш, поэтому я даже не буду писать ... Хорошая работа! :)
Fels
1

Python - 407

from sys import*;o=argv[1];c=argv[2];t=argv[3];p=0;n=False;a=lambda:h not in e;b=lambda s:print(s+(" "*p)+h);r="";e=o+c
for h in t:
 for k in o:
  if h==k:
   if(r in e)and(r!=""):b("")
   else:b("\n")
   p+=2;n=True;break
 for k in c:
  if h==k:
   p-=2
   if(r in e)and(r!=""):b("")
   else:b("\n")
   n=True;break
 if a()and n:print((" "*p)+h,end="");n=False
 elif a():print(h,end="")
 r=h

Нежелательная версия программы:

import sys

open_set = sys.argv[1]
close_set = sys.argv[2]
text = sys.argv[3]
spaces = 0
newline = False
a = lambda : char not in b_set
b = lambda s: print(s + (" " * spaces) + char)
prev = ""
b_set = open_set + close_set

for char in text:
    for bracket in open_set:
        if char == bracket:
            if (prev in b_set) and (prev != ""):
                b("")
            else:
            b("\n")
        spaces += 2
        newline = True
        break
    for bracket in close_set:
        if char == bracket:
            spaces -= 2
            if (prev in b_set) and (prev != ""):
                b("")
            else:
                b("\n")
            newline = True
            break
    if a() and newline:
        print((" " * spaces) + char, end="")
        newline = False
    elif a():
        print(char, end="")
    prev = char

Аргументы программы (по порядку): открывающие скобки, закрывающие скобки и текст для отступа.

Пример ($ - приглашение командной строки):

$ python indent.py "{[(<" "}])>" "abc{xyz{text[note{comment(t{ex}t)abc}]}}"
abc
{
  xyz
  {
    text
    [
      note
      {
        comment
        (
          t
          {
            ex
          }
          t
        )
        abc
      }
    ]
  }
}
golfer9338
источник
0

D (300)

C[] i(C,S)(ref S s,C p){if(!*s)return[];static C[] w;w~=" ";C[] r;C c=s[0];while(c!=p){s=s[1..$];r~=(c=='{'||c=='['||c=='<'?"\n"~w~c~"\n"~i(s,cast(char)(c+2)):c=='('?"\n"~w~c~"\n"~i(s,')'):[c]);c=*s;}w=w[1..$];if(*s)s=s[1..$];c=*s;return" "~w~r~"\n"~w~(c=='}'||c==']'||c=='>'||c==')'?[p]:p~"\n"~w);}

нужна строка с нулевым символом в конце для проверки границ (в противном случае if(*s)необходимо изменить на if(s.length))

чокнутый урод
источник
Обратите внимание, что задача требует, чтобы два набора скобок были частью ввода, а не были жестко закодированы.
Джои
0

Джава

Не codegolf version! Предполагая, что у нас есть эта версия split (), которая включает разделители,

public static String indent(String input, String openPars,
        String closingPars) {
    String re = "["
            + (openPars + closingPars).replace("[", "\\[").replace("]",
                    "\\]") + "]";
    String[] split = inclusiveSplit(input, re, 0);
    int indent = 0;
    StringBuilder sb = new StringBuilder();
    for (String string : split) {
        if (StringUtils.isEmpty(string))
            continue;
        if (closingPars.indexOf(string) != -1) {
            indent--;
        }
        sb.append(StringUtils.repeat(" ", indent * 2));
                    sb.append(string);
                    sb.append("\n");
        if (openPars.indexOf(string) != -1) {
            indent++;
        }
    }
    String string = sb.toString();
    return string;
}
Прашант Бхате
источник
2
StringUtilsне является частью стандарта JDK.
st0le
0

C 284 Не пробелы Символы

Я не фанат запутывания, но хорошо ...

#include<cstdio>
#include<cstring>
#define g printf
#define j char
int main(int a,j**b){int c=0;for(j*f=b[3];*f!='\0';++f){if(strchr(b[1],*f)!=0){g("\n%*c\n%*c",c,*f,c+2,'\0');c+=2;}else if(strchr(b[2],*(f))!=0){c-=2;g("\n%*c",c,*f);if(strchr(b[2],*(f+1))==0)g("\n%*c",c,'\0');}else putchar(*f);}}

Использование: ./program start_brackets end_brackets string_to_parse

Михай Бишог
источник
0

php (187) (153)

function a($s,$o,$e){while(''!=$c=$s[$i++]){$a=strpbrk($c,$o)?2:0;$b=strpbrk($c,$e)?2:0;echo ($a+$b||$r)?"\n".str_pad('',$t-=$b):'',$c;$t+=$a;$r=$a+$b;}}

Функция принимает строку, открывая разделители, заканчивая разделители в качестве аргументов.

migimaru
источник
0

С, 256

Параметры:

  • е - окончательный символ,
  • n - отступ,
  • б открывающие скобки,
  • д закрывающие скобки.

Я разбил код, чтобы избежать горизонтальной полосы прокрутки.

#define r char
#define P(c) putchar(c);
#define N P(x)
#define W printf("%*s",n,"");
r*s,x='\n';i(r e,int n,r*b,r*d){r*t=s,*p;int l=0;W while(*s!=e)    
{if(p=strchr(b,*s)){if(s!=t){N W}P(*s++)N i(d[p-b],n+2,b,d); N W 
P(*s++);l=1;}else{if(l){N W l=0;}P(*s++)}}}

Полная программа составляет 363 символа.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define r char
#define P(c) putchar(c);
#define N P(x)
#define W printf("%*s",n,"");
r*s,x='\n';i(r e,int n,r*b,r*d)
{r*t=s,*p;int l=0;W while(*s!=e)
{if(p=strchr(b,*s)){if(s!=t){N W}
P(*s++)N i(d[p-b],n+2,b,d); N W
P(*s++);l=1;}else{if(l){N W l=0;}
P(*s++)}}}main(int c,r*v[]){s =
v[3];i('\0',0,v[1],v[2]);}
ТКФ
источник
0

VB.net (? C)

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

Imports System.Diagnostics.Debug
Module Module1
  Sub Main(args() As String)
    IndentText(args(0), args(1), args(2)) 'openings, closings, text)
  End Sub
  Sub IndentText(o As String, e As String, t As String)
    Dim x = 0
    Listeners.Add(New Diagnostics.ConsoleTraceListener)
    IndentSize = 2
    For Each c In t
      If o.Contains(c) Then
        WriteLine("")
        WriteLine(c)
        Indent()
        x = 1
      ElseIf e.Contains(c) Then
        If x = 0 Then WriteLine("")
        Unindent()
        WriteLine(c)
        x = 1
      Else
        Write(c)
        x = 0
      End If
    Next
  End Sub
End Module

Использует аргументы командной строки для ввода

args(0) is the indenting chars
args(1) is the undenting chars
args(2) is the text to be indented.
Адам Спейт
источник
0

Powershell, 146 байт

param([char[]]$s,[char[]]$e,[char[]]$f)$f|%{}{if($_-in$s){$o;'  '*$i+$_;$o='  '*++$i;}elseif($_-in$e){$o;'  '*--$i+$_;$o='  '*$i}else{$o+=$_}}{$o}

Ungolfed Объяснение

param([char[]]$start,             # Cast as array of Chars
      [char[]]$end,
      [char[]]$string)
$string | foreach-object { } {    # For every char in string. Empty Begin block
    if ( $_ -in $start ) {        # If char is in start
        $o                        # Print stack ($o)
        '  ' * $i + $_            # Newline, indent, insert start char
        $o = '  ' * ++$i          # Set stack to ident (incremented)
    } elseif ( $_ -in $end ) {    # If char is in end
        $o                        # Print stack
        '  ' * --$i + $_          # Newline, decrement indent, insert end char
        $o = '  ' * $i            # Set stack to indent
    } else {
        $o+ = $_                  # Otherwise add character to stack
    }
} { $o }                          # Print remaining stack (if any)
Джонатан Лич-Пепин
источник
0

C, 181 символов

#define d(m,f)if(strchr(v[m],*s)){puts("");for(j=f;j--;)printf("  ");}
i;main(j,v,s)char**v,*s;{for(s=v[3];*s;s++){d(1,i++)d(2,--i)putchar(*s);d(1,i)if(!strchr(v[2],*(s+1)))d(2,i)}}

Практически самый простой подход, который только можно себе представить. Итерация по строке (v [3]), если это левая скобка (как определено в v [1]), увеличьте уровень отступа, если это правая скобка (как определено в v [2]), уменьшите уровень отступа ,

Коул Камерон
источник
-1

С, 114 121

main(i,x,s,c){while(~(c=getchar()))(s=x)|(x=2*!!strchr("(){}[]<>",c))?s=c-1&x,i-=x-2*s,printf("\n%*c",i-s,c):putchar(c);}

Не очень хорошо, но решение ... пустая строка может появиться до / после в зависимости от того, начинается ли ввод / заканчивается скобками.

С новым ограничением этот подход практически бесполезен для игры в гольф.

esneider
источник
Недостаточно отступает открывающая скобка и выводит пустые строки между последовательными закрывающими.
Джои
@ Joey исправлено, спасибо за отзыв!
Esneider
Он по-прежнему жестко кодирует скобки, пока они должны быть частью ввода. В настоящее время все ответы не соответствуют спецификации.
Джои