Alinhar argumentos de função em suas próprias linhas

16

Dada a entrada de uma sequência que representa uma definição de função, imprima a sequência com novas linhas e espaços inseridos para que os argumentos da função sejam separados por novas linhas e alinhados.

A sequência de entrada seguirá o seguinte padrão:

  • Primeiro, ele começará com um prefixo, que sempre tem pelo menos um caractere e não contém nenhum dos caracteres ,().

  • Um parêntese aberto ( () marcará o início da lista de argumentos.

  • Uma lista de zero ou mais argumentos será seguida. Estes são separados pela cadeia de caracteres ", "(uma vírgula e depois um espaço). Nenhum dos argumentos conterá nenhum dos caracteres ,().

  • Um parêntese próximo ( )) marcará o final da lista de argumentos.

  • Por fim, pode ser encontrado um postfix, que tem zero ou mais caracteres e pode conter os caracteres ,().

A sequência de entrada consistirá apenas em ASCII imprimível (o que significa que nunca conterá uma nova linha).

A saída deve ser:

  • O prefixo, copiado literalmente, e o parêntese aberto.

  • A lista de argumentos, desta vez separada não por ", "vírgula, nova linha e quantos espaços forem necessários para alinhar verticalmente o primeiro caractere de cada argumento.

  • O ponto final e o pós-fixos (se existir) literalmente.

Como esse é o , o código mais curto em bytes será vencedor.

Casos de teste (formato: entrada de linha única seguida de saída seguida de nova linha dupla):

def foo(bar, baz, quux):
def foo(bar,
        baz,
        quux):

int main() {
int main() {

fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {
fn f(a: i32,
     b: f64,
     c: String) -> (String, Vec<i32>) {

function g(h) {
function g(h) {

def abc(def, ghi, jkl, mno)
def abc(def,
        ghi,
        jkl,
        mno)

x y z(x, y, z) x, y, z)
x y z(x,
      y,
      z) x, y, z)
Maçaneta da porta
fonte

Respostas:

7

Haskell, 115 bytes

import Data.Lists
f x|(a,b:c)<-span(/='(')x,(d,e)<-span(/=')')c=a++b:intercalate(",\n "++(a>>" "))(splitOn", "d)++e

Exemplo de uso:

*Main> putStrLn $ f "fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {"
fn f(a: i32,
     b: f64,
     c: String) -> (String, Vec<i32>) {

Como funciona:

bind
  a: everything before the first (
  b: the first (
  c: everything after the first (
  d: everything of c before the first )
  e: everything of c from the first ) to the end

construct the output string by concatenating
  a
  b
  splitting d at the argument separator ", " and rejoining it with ",\n " followed by (length a) spaces    
  e
nimi
fonte
a>>" "é realmente inteligente ...
Actorclavilis
4

Japonês, 23 bytes

¡Y?X:Xr',",
"+SpUb'(}')

Teste online!

Como funciona

               // Implicit: U = input string
¡        }')   // Map each item X and index Y in U.split(")") to:
Y?X            //  If Y is non-zero, X. This keeps e.g. "(String, Vec<i32>)" from being parsed.
:Xr',",\n"+    //  Otherwise, X with each comma replaced with ",\n" concatenated with
SpUb'(         //  U.indexOf("(") spaces.
               // Implicit: re-join with ")", output
ETHproductions
fonte
3

Perl, 62 52 + 2 = 54 bytes

s/\(.*?\)/$a=$"x length$`;$&=~s|(?<=,)[^,]+|\n$a$&|gr/e

Requer a -pbandeira:

$ echo "x y z(x, y, z) x, y, z)
fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {" | \
perl -pe's/\(.*?\)/$a=$"x length$`;$&=~s|(?<=,)[^,]+|\n$a$&|gr/e'
x y z(x,
      y,
      z) x, y, z)
fn f(a: i32,
     b: f64,
     c: String) -> (String, Vec<i32>) {

Como funciona:

# '-p' reads first line into $_ and will also auto print at the end
s/\(.*?\)/             # Match (...) and replace with the below
  $a=$"x length$`;     # $` contains all the content before the matched string
                       # And $" contains a literal space 
  $&=~s|               # Replace in previous match
    (?<=,)[^,]+        # Check for a , before the the string to match
                       # This will match ' b: f64', ' c: String'
  |\n$a$&|gr/e         # Replace with \n, [:spaces:] and all the matched text
andlrc
fonte
3

Retina, 31 bytes

(?<=^([^(])*\([^)]*,) 
¶ $#1$* 

Observe os espaços no final das duas linhas.

Substituímos todo espaço que possui o regex ^([^(])*\([^)]*,antes dele. A sequência de substituição será uma nova linha e o número de capturas com ([^(])*mais um espaço.

Uma explicação mais coerente vem depois.

Experimente online aqui.

randomra
fonte
3

ES6, 68 67 bytes

s=>s.replace(/\(.*?\)/,(s,n)=>s.replace/, /g, `,
 `+` `.repeat(n)))

Isso funciona extraindo a lista de argumentos da string original e substituindo cada separador de argumentos por recuo calculado a partir da posição da lista de argumentos na string original.

Editar: salvou 1 byte graças a @ETHproductions.

Neil
fonte
Fiquei me perguntando por que você fez em .split`, `.join(...)vez de .replace(...). Acontece que o outro é um byte mais curto:s=>s.replace(/\(.*?\)/,(s,n)=>s.replace(/, /g,`,\n `+` `.repeat(n)))
ETHproductions 9/16
2

Pyth, 35 30 bytes

+j++\,b*dhxz\(c<zKhxz\)", ">zK

Experimente aqui!

Explicação:

+j++\,b*dhxz\(c<zKhxz\)", ">zK    # z = input()

                 Khxz\)           # Get index of the first ")"
               <z                 # Take the string until there...
              c        ", "       # ...and split it on the arguments
 j                                # Join the splitted string on...
  ++                              # ...the concatenation of...
    \,b                           # ...a comma followed by a newline...
       *dhxz\(                    # ...followed by the right amount of spaces = index of the first "(" + 1
+                         >zK     # Concat the resulting string with the postfix
Denker
fonte
2

Groovy, 137 89 95 bytes

O Groovy não é a "Ferramenta certa para o trabalho" ™. Edit: Ele funciona muito bem quando você tem alguém com um cérebro usá-lo ...

f={s=(it+' ').split(/\0/)
s[0].replace(',',',\n'+(' '*it.indexOf('(')))+')'+s[1..-1].join(')')}

Testes:

println f("def foo(bar, baz, quux):")
println f("int main() {")
println f("fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {")
println f("function g(h) {")
println f("def abc(def, ghi, jkl, mno)")
println f("x y z(x, y, z) x, y, z)")

Um pouco não-destruído:

f = {String it ->
    def str = (it + ' ').split(/\)/)
    return (str[0].replace (',', ',\n'+(' ' * it.indexOf('('))) + ')' + str[1])
}
J Atkin
fonte
1

Retina , 47 bytes

A contagem de bytes assume a codificação ISO 8859-1.

m+`^(([^(]+.)[^,)]+,) (.+)
$1¶$2$3
T`p` `¶.+?\(

Experimente online!

Martin Ender
fonte
1

JavaScript (ES6), 85

s=>s.replace(/^.*?\(|[^),]+, |.+/g,(x,p)=>[a+x,a=a||(p?`
`+' '.repeat(p):a)][0],a='')

Teste

f=s=>s.replace(/^.*?\(|[^),]+, |.+/g,(x,p)=>[a+x,a=a||(p?`
`+' '.repeat(p):a)][0],a='')

console.log=x=>O.textContent+=x+'\n'

;['def foo(bar, baz, quux):',
  'int main() {',
  'fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {',
  'function g(h) {',
  'def abc(def, ghi, jkl, mno)',
  'x y z(x, y, z) x, y, z)']
.forEach(t=>console.log(t+'\n'+f(t)+'\n'))
<pre id=O></pre>

edc65
fonte
Me desculpe, eu estava enganando, estava executando o código no meu console e a saída era algo assim: "x y z(xcomo você pode ver, "é por isso que eu estava pensando que era um espaço livre. Daí a exclusão
andlrc 8/16/16
@ dev-null que acontece comigo o tempo todo.
Edc65
0

Geléia , 39 bytes

ṣ”)Ḣṣ”(Ṫ©œṣ⁾, ji”(⁶ẋƊ⁾,¶;ƊḢ,j®${jʋ@œṣ®$

Experimente online!

Erik, o Outgolfer
fonte