Converter expoentes em arte ASCII

28

Tarefa

Sua tarefa é converter seqüências de caracteres como esta:

abc^d+ef^g + hijk^l - M^NO^P (Ag^+)

Para strings como este:

   d   g       l    N P    +
abc +ef  + hijk  - M O  (Ag )

Qual é uma aproximação a abc d + ef g + hijk l - M N O P (Ag + )

Em palavras, aumente os caracteres diretamente ao lado dos sinais de intercalação para a linha superior, um caractere para um sinal de intercalação.

Especificações

  • Espaços em branco à direita na saída são permitidos.
  • Nenhum sinal de intercalação como m^n^oserá dado como entrada.
  • Um sinal de intercalação não será seguido imediatamente por um espaço ou por outro sinal de intercalação.
  • Um sinal de intercalação não será precedido imediatamente por um espaço.
  • Todos os sinais de intercalação serão precedidos por pelo menos um caractere e seguidos por pelo menos um caractere.
  • A sequência de entrada conterá apenas caracteres ASCII imprimíveis (U + 0020 - U + 007E)
  • Em vez de duas linhas de saída, você pode gerar uma matriz de duas seqüências.

Para aqueles que falam regex: a string de entrada corresponderá a este regex:

/^(?!.*(\^.\^|\^\^|\^ | \^))(?!\^)[ -~]*(?<!\^)$/

Entre os melhores

Freira Furada
fonte
2
@TimmyD "A string de entrada conterá apenas caracteres ASCII imprimíveis (U + 0020 - U + 007E)"
Freira
3
Por que parar nos expoentes? Eu quero algo que lida com H_2O!
305 Neil
1
@ Neil Faça o seu próprio desafio, então, e eu posso encerrá-lo como uma duplicata dele. :)
Leaky Nun
1
Com base no seu exemplo, eu diria que eles são superindices , não necessariamente expoentes
Luis Mendo
4
Quem fala regex vem de um país altamente regular, onde a expressão é fortemente restringida. A principal causa de morte é o retorno catastrófico.
David Conrad

Respostas:

19

V , 15 14 bytes

ÄÒ +òf^xxé kPj

Experimente online!

Uma solução bastante direta. O desafio perfeito para o V!

Explicação:

Ä                "Duplicate this current line
 Ò               "Replace this line with spaces
   +             "Move to the beginning of the next line
    ò         ò  "Recursively (The second ò is implicit):
     f^          "  Find a caret
       xx        "  Delete two characters. The second will be saved into the main register
         é       "  Insert a space
           k     "  Move up
            P    "  Paste from the main register
             j   "  Move down

Convenientemente, com base em como a recursão funciona, isso será executado uma vez para cada sinal de intercalação.

DJMcMayhem
fonte
2
O vim é a linguagem perfeita para esse desafio. +1
Downgoat 26/07/16
18

Queijo Cheddar, 77 72 67 bytes

l->l.chars.vfuse.replace("^\n"," ").lines.map(j->"%-2s"%j).turn(3)

Sem regex!

Eu amo essa resposta, pois é uma demonstração maravilhosa das habilidades do Cheddar. Principalmente graças à função de substituição adicionada por Conor. O PR para dev nunca foi feito, portanto a função de substituição existe apenas neste ramo (atualização: eu fiz o PR e agora ele está no último ramo beta com o qual você pode instalar npm install -g cheddar-lang)

Eu encontrei uma maneira de jogar golfe, mas infelizmente uma supervisão resulta nisso quando os comprimentos dos itens não são os mesmos:

["   denifednud   denifednug       denifednul    denifednuN denifednuP    denifednu+ ", "abcdenifednu +efdenifednu  + hijkdenifednu  - Mdenifednu Odenifednu  (Agdenifednu )"]

Eu poderia ter salvo muitos bytes usando regex e, na verdade, acabei de criar regex para o Cheddar ... o único problema é que não há funções de regex: /

Explicação

l->                    // Function take input as `l`
   l.chars             // Get array of chars in input
   .vfuse              // Join with newlines
   .replace("^\n"," ") // Replace `^\n` with a space globally
   .lines              // Get the lines (see below for more details on what this returns)
   .map(j->            // Loop through each "line" `j` is arg
       "%-2s"          // C-like printf format.
                       // think of as: padRight(j, " ", 2)
                       // see below for more details
        % j            // Pass j as the string to insert
   ).turn(3)           // Turn the string 270 degrees (see below)
   .vfuse              // Vertically fuse to get result (this is not needed as we can output an array of the lines)

Para entender melhor. É isso que .linesretorna para1^2

["1", " 2"]

o .turncom rodar isto:

1
 2

para dentro:

 2
1

Outro exemplo que tornará mais claro:

1
 2
2
 2

torna-se:

 2 2
1 2

Por que formatar?

O que %-2sestá fazendo é bem simples. %especifica que estamos iniciando um "formato" ou que uma variável será inserida nessa sequência neste momento. -significa colocar a corda com o botão direito e 2é o comprimento máximo. Por padrão, ele preenche os espaços. sapenas especifica que é uma string. Para ver o que faz:

"%-2s" % "a"  == "a "
"%-2s" % " a" == " a"
Downgoat
fonte
2
: D sempre voto cheddar.
DJMcMayhem
@DrGreenEggsandIronMan: D obrigado
Downgoat
1
Cheddar tem um turnmétodo para cordas?
TuxCrafting 27/07/16
6
-1 O nome desse idioma sempre me deixa com fome.
deixou de vez counterclockwis
@ TùxCräftîñg apenas para matrizes 2D, razão pela qual usei .lines para obter as linhas.
Downgoat 27/07/16
10

Perl, 21 + 1 = 22 bytes

say'';s/\^(.)/♥[A\1↓/

Corra com a -pbandeira. Substitua por um ESCbyte bruto ( 0x1b) e por uma guia vertical ( 0x0b).

A guia vertical é idéia de Martin Ender. Ele salvou dois bytes! Obrigado.

Lynn
fonte
Você não precisaria mover o cursor para baixo de uma linha no início para que os expoentes não se sobrepusessem ao último prompt do console?
Martin Ender
Eu não tinha certeza disso, sim. Eu assumi que tinha tanto espaço quanto preciso, mas talvez isso seja um pouco barato. (Em geral, eu não sou muito orgulhoso de usar movimentos do cursor para resolver este tipo de problema, mas é a primeira coisa que veio à mente ...)
Lynn
2
Eu acho que é uma boa solução, mas o resultado deve ser visualmente indistinguível de imprimir a string conforme o esperado.
Martin Ender
1
Que solução adorável
Thomas Weller
7

JavaScript (ES6), 56 55 bytes

s=>[/.(\^(.))?/g,/\^.(())/g].map(r=>s.replace(r,' $2'))

Regexps para o resgate, é claro. O primeiro substitui todos os caracteres por espaços, a menos que encontre um sinal de intercalação; nesse caso, ele exclui o sinal de intercalação e mantém o caracter após. (É garantido que esses caracteres existam.) O segundo é o óbvio para substituir cada sinal de intercalação e seu caractere a seguir por um espaço.

Edit: Salvo 1 byte, graças a @Lynn, que criou uma maneira de reutilizar a sequência de substituição para a segunda substituição, permitindo que a substituição seja mapeada sobre uma matriz de regexps.

Neil
fonte
2
Parece que s=>[/.(\^(.))?/g,/\^.(())/g].map(r=>s.replace(r,' $2'))é um byte mais curto.
26416 Lynn
@ Lynn Isso é realmente um truque astuto!
26416 Neil
7

Python 3, 157 101 98 85 83 74 bytes

Essa solução monitora se o caractere anterior era ^e decide se deve enviar para a primeira ou segunda linha com base nisso.

Saídas como uma matriz de ['firstline', 'secondline'].

a=['']*2
l=0
for c in input():x=c=='^';a[l]+=c*x;a[~l]+=' '*x;l=x
print(a)

Guardado 13 15 bytes graças a @LeakyNun!

Guardado 7 bytes graças a @Joffan!

Cobre
fonte
1
Bom autômato em estado finito.
Freira vazando
Seria melhor a=['','']concatenar ' 'e centrar diretamente em a[l]e a[~l]?
achou
6

Python 2, 73 bytes

l=['']*2;p=1
for c in input():b=c!='^';l[p]+=c*b;l[~p]+=' '*b;p=b
print l

Sem regex. Lembra se o caractere anterior era ^e coloque o caractere atual na linha superior ou inferior com base nisso, e um espaço no outro.

xnor
fonte
4

Pitão, 17 bytes

CcsmX~Z1j;d;cQ\^2

             Q      input string
            c \^    split on '^'
   m                map for sections d:
    X      ;          insert a space at index:
     ~Z1                the old value of Z (initially 0), before setting Z to 1
                      into:
        j;d             the section joined on spaces
  s                 concatenate
 c              2   chop into groups of 2
C                   transpose

Retorna uma matriz de 2 strings. Anexe um jingresso a eles com uma nova linha.

Experimente online .

Anders Kaseorg
fonte
1
Não consigo parar de me perguntar como o seu sobrenome é pronunciado. : D
Lynn
4

MATL , 18 bytes

94=t1YSt~&vG*cw~Z)

Experimente online!

94=    % Take input implicitly. Create logical array of the same size that contains
       % true for carets, false otherwise
t      % Push a copy of this array
1YS    % Circularly shift 1 unit to the right. This gives an array that contains true
       % for the elements right after a caret (superindices), and false for the rest 
t~     % Push a copy and negate
&v     % Concatenate vertically. This gives a 2D, 2-row array
G*     % Push the input again, multiply with broadcast. This gives a 2D array in
       % which the first row contains the superindices (characters after a caret)
       % and 0 for the rest; and the second row contains the non-superindices and
       % 0 for the superindices
c      % Convert to char
w      % Swap. Brings to top the array containing true for carets and false otherwise
~      % Negate
Z)     % Use as logical index to remove rows that contain carets. Display implicitly
Luis Mendo
fonte
4

Ruby, 47 + 1 ( -nsinalizador) = 48 bytes

puts$_.gsub(/\^(.)|./){$1||" "},gsub(/\^./," ")

Execute-o assim: ruby -ne 'puts$_.gsub(/\^(.)|./){$1||" "},gsub(/\^./," ")'

Value Ink
fonte
Eu acho que você pode economizar 1 byte usando $_=$_.gsub(/\^(.)|./){$1||" "}+gsub(/\^./," ")e em -pvez de -n.
Dom Hastings
1
@DomHastings, independentemente de funcionar ou não, seu código não parece ter uma nova linha, e adicionar +$/significa que ele não salvará bytes. putslança a nova linha para você automaticamente quando ,está presente entre argumentos.
Value Ink
Ah ... eu testei usando, ruby -p ... <<< 'input'mas concordo, se está faltando a nova linha, não é bom! Na verdade, eu poderia ter uma nova linha anexada nos meus testes mais cedo ... Mas estava no trabalho, então não posso verificar!
Dom Hastings
@DomHastings Olhando novamente, acho que é porque getsinclui a nova linha à direita na maioria das vezes, mas se você inserir um arquivo que não contém a nova linha à direita, ela não aparecerá e a saída estará errada. . Teste seu código com o ruby -p ... inputfileRuby, pois o redireciona getspara o arquivo se for um argumento de linha de comando.
Value Ink
Entendi, faz todo o sentido. Eu acho que uma nova linha no arquivo também resolveria o problema. Eu não sou um Rubyist proficiente de forma alguma, então sinto que aprendi um pouco mais sobre isso hoje. Obrigado!
Dom Hastings
3

Python (2), 76 68 67 bytes

-5 Bytes graças a @LeakyNun

-3 Bytes graças a @ KevinLau-notKenny

-1 Byte graças a @ValueInk

-0 bytes graças a @DrGreenEggsandIronMan

import re
lambda i,s=re.sub:[s("(?<!\^).\^?"," ",i),s("\^."," ",i)]

Essa função Lambda anônima toma a string de entrada como seu único argumento e retorna as duas linhas de saída separadas por uma nova linha. Para chamá-lo, dê um nome escrevendo "f =" antes dele.

Regex bastante simples: a primeira parte substitui o seguinte por um espaço: qualquer caractere e um sinal de intercalação de cenoura ou apenas um caractere, mas somente se não houver intercalação antes deles. A segunda parte substitui qualquer sinal de intercalação na cadeia de caracteres e o caractere após um espaço.

KarlKastor
fonte
@LeakyNun: Eu estava por algum motivo me perguntando se 1. também vale se eu importar bibliotecas. Estava copiando 2. para esta pergunta agora mesmo quando vi seu comentário. Obrigado a você e Kevin!
KarlKastor
Você pode tirar um byte comfrom re import*
DJMcMayhem
@DrGreenEggsandIronMan Parece usar exatamente o mesmo número de bytes. (veja acima)
KarlKastor 27/07
Mantenha a declaração de importação antiga e faça lambda i,s=re.sub:[s("(?<!\^).\^?"," ",i),s("\^."," ",i)]por -1 byte
Value Ink
2

Retina, 16 bytes

S`^
\^(.)
♥[A$1↓

Um porto da minha resposta Perl, apontado por Martin Ender. Substitua por um ESCbyte bruto ( 0x1b) e por uma guia vertical ( 0x0b).

Lynn
fonte
2

shell + TeX + catdvi, 51 43 bytes

tex '\empty$'$1'$\end'>n;catdvi *i|head -n2

Usa texpara digitar algumas belas matemáticas e depois usa catdvipara fazer uma representação de texto. O comando head remove o lixo eletrônico (numeração de página, linhas novas à direita) que estiver presente.

Edit: Por que a coisa longa e adequada e redireciona para /dev/nullquando você pode ignorar os efeitos colaterais e gravar em um único arquivo de letra?


Exemplo

Entrada: abc^d+ef^g + hijk^l - M^NO^P (Ag^+)

Saída TeX (cortada para a equação): Matemática "linda"! Saída final:

   d   g     l  N P   +
abc +ef +hijk -M O (Ag )

Pressupostos: inicie no diretório vazio (ou especificamente um diretório sem nome que termina em "i"). Entrada é um argumento único para o script de shell. A entrada não é uma sequência vazia.

Alguém me diz se isso é abuso de regras, especialmente catdvi.

algmyr
fonte
2

Haskell, 74 56 55 bytes

g('^':c:r)=(c,' '):g r
g(c:r)=(' ',c):g r
g x=x
unzip.g

Retorna um par de strings. Exemplo de uso: unzip.g $ "abc^d+e:qf^g + hijk^l - M^NO^P: (Ag^+)"->(" d g l N P + ","abc +e:qf + hijk - M O : (Ag )")

gfaz uma lista de pares, onde o primeiro elemento é o caractere na linha superior e o segundo elemento é o caractere na linha inferior. unziptransforma em um par de listas.

Edit: @xnor sugeriu unzipque economiza 18 bytes. A @Laikoni encontrou mais um byte para economizar. Obrigado!

nimi
fonte
Você pode fazer j=unzip.g?
Xnor
@xnor: oh, como é estúpido da minha parte não ver isso sozinho! Muito obrigado!
nimi 28/07
Você pode substituir g[]=[]por g x=xpara salvar um byte.
Laikoni
@Laikoni: Bem avistado! Obrigado!
nimi
1

Perl, 35 bytes

Código de 34 bytes + 1 para -p

$_=s/\^(.)|./$1||$"/ger.s/\^./ /gr

Uso

perl -pe '$_=s/\^(.)|./$1||$"/ger.s/\^./ /gr' <<< 'abc^d+ef^g + hijk^l - M^NO^P (Ag^+)'
   d   g       l    N P    + 
abc +ef  + hijk  - M O  (Ag )

Nota: É exatamente o mesmo que a resposta da Value Ink , que espiei depois. Removerá se necessário, pois isso realmente não adiciona à solução Ruby.

Dom Hastings
fonte
1

Java 8 lambda, 132 128 112 caracteres

i->{String[]r={"",""};for(char j=0,c;j<i.length();j++){c=i[j];r[0]+=c==94?i[++j]:32;r[1]+=c==94?32:c;}return r;}

A versão ungolfed é assim:

public class Q86647 {

    static String[] printExponents(char[] input) {
        String[] result = {"",""};
        for (char j = 0, c; j < input.length(); j++) {
            c = input[j];
            result[0] += c == 94 ? input[++j] : 32;
            result[1] += c == 94 ? 32 : c;
        }
        return result;
    }
}

Saída como uma matriz, simplesmente verificando se existe um sinal de intercalação e, se houver, o próximo caractere será colocado na linha superior, caso contrário, haverá um espaço.


Atualizações

Caracteres substituídos por seus valores ascii para salvar 4 caracteres.

Agradecemos a @LeakyLun por apontar para usar uma matriz de caracteres como entrada.

Também obrigado a @KevinCruijssen por mudar intpara charpara salvar mais alguns caracteres.

Frozn
fonte
Você pode tentar inserir char[]e usar for(char c:i)para ver se a contagem de bytes pode ser reduzida.
Freira vazando
Você pode reduzir para 110 bytes usando: i->{String[]r={"",""};for(char j=0,c;j<i.length;j++){c=i[j];r[0]+=c==94?i[++j]:32;r[1]+=c==94?32:c;}return r;}with "abc^d+ef^g + hijk^l - M^NO^P (Ag^+)".toCharArray()como entrada. ( Ideone dessas mudanças. )
Kevin Cruijssen
1

Coco , 122 114 96 bytes

Edit: 8 26 bytes abaixo com a ajuda de Leaky Nun.

def e(s,l)=''==l and s or"^"==l[0]and l[1]+e(s+' ',l[2:])or' '+e(s+l[0],l[1:])
f=print..e$('\n')

Então, como eu aprendi hoje, o python tem um operador condicional ternário, ou de fato dois deles: <true_expr> if <condition> else <false_expr>e o <condition> and <true_expr> or <false_expr>último vem com um caractere a menos.
Uma versão em conformidade com python pode ser ideonada .


Primeira tentativa:

def e(s,l):
 case l:
  match['^',c]+r:return c+e(s+' ',r)
  match[c]+r:return' '+e(s+c,r)
 else:return s
f=print..e$('\n')

Ligando com f("abc^d+ef^g + hijk^l - M^NO^P (Ag^+)")impressões

   d   g       l    N P    +
abc +ef  + hijk  - M O  (Ag )

Alguém já tentou jogar golfe no coco? Ele enriquece o python com conceitos de programação mais funcionais, como a correspondência de padrões e a concatenação de funções (com ..) usadas acima. Como esta é minha primeira tentativa de coco, qualquer dica seria apreciada.

Definitivamente, isso pode ser reduzido, pois qualquer código python válido também é válido coco e respostas mais curtas foram publicadas, no entanto, tentei encontrar uma solução puramente funcional.

Laikoni
fonte
Eu acho que você pode usar operadores ternários ( x and y or z) para substituir o case.
Freira vazando
Você pode até usar em s[0]=="^"vez dematch['^',c]+r in l
Leaky Nun
@LeakyNun Quando substituo match['^',c]+rpor s[0]=="^", então ce rnão estamos mais vinculados. Como isso ajudaria?
Laikoni 28/07
Você pode usar s[1]para substituir ce s[2:]substituir r.
Freira vazando
então você pode usar ternário agora.
Leaky Nun
0

Dyalog APL, 34 bytes

{(0 1=⊂b/¯1⌽b){⍺\⍺/⍵}¨⊂⍵/⍨b←⍵≠'∧'}

Retorna um vetor de dois elementos com as duas linhas

Execução da amostra (a parte superior na frente é formatar o vetor de dois el. Para consumo humano):

      ↑{(0 1=⊂b/¯1⌽b){⍺\⍺/⍵}¨⊂⍵/⍨b←⍵≠'∧'}'abc∧d+ef∧g + hijk∧l - M∧NO∧P (Ag∧+)'
   d   g       l    N P    + 
abc +ef  + hijk  - M O  (Ag )
lstefano
fonte
Ao seu comentário sobre minha pergunta sobre o código não fazer nada: sim, esse código que você coloca conta.
haykam
0

PowerShell v2 +, 88 83 bytes

-join([char[]]$args[0]|%{if($c){$_;$b+=' '}elseif($_-94){$b+=$_;' '}$c=$_-eq94});$b

Um pouco mais do que os outros, mas mostra um pouco de magia do PowerShell e uma lógica um pouco diferente.

Essencialmente, o mesmo conceito que o Python responde - iteramos a entrada caractere por caractere, lembramos se o anterior era um sinal de intercalação ( $c) e colocamos o caractere atual no local apropriado. No entanto, a lógica e o método para determinar onde a saída é manipulada de maneira um pouco diferente e sem uma tupla ou variáveis ​​separadas - testamos se o caractere anterior era um sinal de intercalação e, se for o caso, transmitimos o caractere para o pipeline e concatenamos um espaço no $b. Caso contrário, verificamos se o caractere atual é um sinal de intercalação elseif($_-94)e, desde que não seja, concatenamos o caractere atual $be produzimos um espaço para o pipeline. Finalmente, definimos se o caractere atual é um sinal de intercalação para a próxima rodada.

Reunimos esses caracteres do pipeline juntos em parênteses, os encapsulamos em um -joinque os transforma em uma string e deixamos isso junto com $bo pipeline. A saída no final está implícita com uma nova linha entre elas.

Para comparação, aqui está uma porta direta da resposta Python do @ xnor , em 85 bytes :

$a=,''*2;[char[]]$args[($l=0)]|%{$a[!$l]+="$_"*($c=$_-ne94);$a[$l]+=' '*$c;$l=!$c};$a
AdmBorkBork
fonte
0

Gema, 42 41 caracteres

\^?=?@set{s;$s }
?=\ @append{s;?}
\Z=\n$s

O gema processa a entrada como fluxo, portanto, você deve resolvê-la em uma única passagem: a primeira linha é gravada imediatamente como processada, a segunda linha é coletada na variável $ s e, em seguida, a saída é finalizada.

Exemplo de execução:

bash-4.3$ gema '\^?=?@set{s;$s };?=\ @append{s;?};\Z=\n$s' <<< 'abc^d+ef^g + hijk^l - M^NO^P (Ag^+)'
   d   g       l    N P    +  
abc +ef  + hijk  - M O  (Ag )
homem a trabalhar
fonte
0

Goma de canela, 21 bytes

0000000: 5306 6533 bd92 d1db 8899 8381 a2f8 8f8c  S.e3............
0000010: 1230 249e a1                             .0$..

Não concorrente. Experimente online.

Explicação

Eu não sou muito jogador de regex, então provavelmente há uma maneira melhor de fazer isso.

A cadeia de caracteres descompacta para:

S(?<!\^)[^^]& &\^&`S\^.& 

(observe o espaço à direita)

O primeiro Sestágio recebe entrada e usa um lookbehind negativo para substituir todos os caracteres, exceto os sinais de intercalação por nenhum cursor anterior, por um espaço e, em seguida, exclui todos os sinais de intercalação. Em seguida, ele envia imediatamente a sequência de entrada modificada com uma nova linha e remove esse Sestágio. Como o STDIN agora está esgotado e o estágio anterior não forneceu nenhuma entrada, o próximo Sestágio recebe a última linha do STDIN novamente e substitui todos os pontos de intercalação seguidos por qualquer caractere por um espaço e gera esse resultado.

No código psledo Perl:

$first_stage_sub_1 = ($input =~ s/(?<!\^)[^^]/ /gr);
$first_stage_sub_2 = ($first_stage_sub_1 =~ s/\^//gr);
print $first_stage_sub_2, "\n";

$second_stage_sub = ($input =~ s/\^./ /gr);
print $second_stage_sub, "\n";
um spaghetto
fonte
0

J , 28 27 bytes

0|:t#]{."0~_1-_1|.t=.'^'~:]

Experimente online!

                  t=.'^'~:]    0 for ^, 1 for the rest, define t
              _1|.             Shift right, now zeroes are for superscripts         
     ]{."0~_1-                 Prepend that many spaces to each character
   t#                          Remove the rows with carets
0|:                            Transpose

Deve haver uma maneira melhor ...

FrownyFrog
fonte