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


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}

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


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

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

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

@ Джои заметил, что я скоро исправлю это. Спасибо
Хуан

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
)

Вам нужны пробелы после 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=""}}}}

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}]}}' '[{(<' ']})>'

Очень хорошая концепция, @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
      }
    ]
  }
}

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

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


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

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

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


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

@ Joey исправлено, спасибо за отзыв!
Esneider

Он по-прежнему жестко кодирует скобки, пока они должны быть частью ввода. В настоящее время все ответы не соответствуют спецификации.
Джои
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.