Panfix para infix entre parênteses

16

Quylthulg é uma linguagem de Chris Pressey que tenta resolver o problema da notação infix usando o que chama de panfix :

como o postfix, o panfix não exige a implantação de artifícios arcanos, como parênteses, para substituir uma precedência padrão do operador. Ao mesmo tempo, o panfix permite que os termos sejam especificados na mesma ordem e maneira que o infixo, uma notação inquestionavelmente natural e intuitiva para aqueles que se acostumaram a ele.


Como você obtém a conveniência da notação infix, juntamente com a ambiguidade de prefixo ou postfix? Use todos os três, é claro!

=y=+*3*x*+1+=

Mais formalmente, vamos +ser um operador e ae bser expressões. Então (a+b)é uma expressão de infixo válida (entre parênteses), a representação panfix dessa expressão é +a+b+, onde a justaposição representa concatenação.

Seu objetivo é pegar uma string panfix e convertê-la em infix totalmente entre parênteses:

(y=((3*x)+1))

Para simplificar, faremos as seguintes alterações:

  • Os operadores podem consistir apenas em dois caracteres únicos (você pode escolher qualquer um, mas aqui vou usar *e +).
  • Existe apenas um literal, que consiste em outro caractere distinto (você pode escolher qualquer, mas aqui vou usar _).
  • A entrada será uma expressão panfix bem formada.

Por complexidade , faremos as seguintes alterações:

  • Os operadores podem consistir em qualquer número positivo de caracteres, não apenas um.

Isso torna o desafio mais complicado, porque você não pode determinar necessariamente como uma determinada substring de caracteres do operador é particionada sem observar o restante da string.

Aqui está uma implementação de referência para o desafio, cortesia de @ user202729.

Casos de teste

format: input -> output
+*+_*+_*+++_+*+_*+_*+++ -> ((_*+_)+(_+(_*+_)))
**++*+***++_+_++_+*++*+***_*++*+*****_**_*_*** -> ((((_+_)+_)*++*+***_)*(_*(_*_)))
***_**_***_* -> ((_**_)*_)
+_+_+ -> (_+_)
*+*+++**+***+++++_*+*+++**+***+++++_*+*+++**+***+++++ -> (_*+*+++**+***+++++_)
*++++*+*_*_*+*+++****+_++****+_++****++*+*+++_*+++ -> (((_*_)+*+(_++****+_))*+++_)
+**+_*+_*+*_*+*_*+*_+*_+**+ -> (((_*+_)*_)+(_*(_+*_)))
+**+++++_+++++_+++++*_*+*+_++++++_+++++_+++++++* -> (((_+++++_)*_)+*(_+(_+++++_)))
+*+*+_+*+_+*+*_*+*_*+*+_+*+_+*+*+ -> (((_+*+_)*_)+(_*(_+*+_)))
**_**_**_*_****_* -> ((_*(_*(_*_)))*_)

Eu usei esse programa para gerar strings infix para esse desafio (a conversão para panfix era trivial, mas a reversão não é).

Esolanging Fruit
fonte
2
O inverso
Conor O'Brien
2
Relacionado
HyperNeutrino
6
Caso de teste sugerido: **_**_**_*_****_*. As respostas que eu testei falharam nesta.
Nitrodon
1
Posso ter espaços extras na minha saída, por exemplo (_ + _)?
Ton Hospel
2
@TonHospel Sure.
Esolanging Fruit

Respostas:

6

Prolog (SWI) , 194 163 bytes

Economizou 31 bytes usando esta dica de 0 ' !

[C|T]/O/R:-C\=x,(T/P/R,concat(C,P,O);O=C,R=T).
[x|R]-x-R.
L-X-R:-L/O/A,A-Y-B,B/O/C,C-Z-D,D/O/R,atomics_to_string(['(',Y,O,Z,')'],X).
X^P:-string_chars(X,L),L-P-[].

O operador ^pega como argumento esquerdo uma string contendo uma expressão panfix e define seu argumento direito como uma string contendo a expressão infix entre parênteses correspondente. Ele usa xcomo literal no lugar de _.

Experimente online!

Explicação

Como o Prolog é uma linguagem declarativa, basta descrever a relação entre uma panfix e uma expressão entre parênteses.

A explicação usa esta versão um pouco não destruída:

oper([C|T],O,R) :- C\=x, oper(T,P,R), concat(C,P,O).
oper([C|T],C,T).

expr([x|R],x,R).
expr(L,X,R) :- oper(L,O,A), expr(A,Y,B), oper(B,O,C), expr(C,Z,D), oper(D,O,R),
               atomics_to_string(['(',Y,O,Z,')'],X).

parenthesize(X,P) :- string_chars(X,L), expr(L,P,[]).

Nossa principal produção é parenthesize, que recebe uma expressão panfix Xcomo uma string e envia a expressão infix entre parênteses correspondente Pcomo uma string. Ele usa string_charspara converter a string de entrada em uma lista de caracteres e simplesmente a passa para expr.

exprrecebe uma lista de caracteres L, analisa a primeira expressão panfix encontrada Le envia o equivalente entre parênteses Xe o restante da lista de caracteres R. Existem dois tipos possíveis de expressões:

  • Se o primeiro caractere de Lé x, então a expressão é xe o restante é tudo após o x.
  • Caso contrário, analise um operador O(veja operabaixo); analisar uma expressão Y; analisar Onovamente; analisar outra expressão Z; e analise Ouma terceira vez. O restante é tudo após a terceira instância de O. A expressão é o resultado da junção Y, Oe Z, entre parênteses, em uma sequência.

operleva em uma lista de caracteres, onde está o primeiro caractere Ce o restante T; ele analisa um operador (ou seja, uma execução de um ou mais caracteres do operador) e envia o operador Oe o restante da lista de caracteres R. Para formar um operador, o personagem Cdeve ser algo diferente de x; também

  • um operador Pdeve ser analisável de T, com o restante R; nesse caso, Oé a concatenação de Ce P; ou,
  • Oé o caractere único C; neste caso, Ré justo T.

Um exemplo trabalhado

Vamos dar a entrada +*+x+x++*x+*para um exemplo.

  • Queremos analisar uma expressão de +*+x+x++*x+*. Como não começa x, analisamos um operador desde o início.
  • operanalisará o maior operador possível, por isso tentamos +*+.
    • Em seguida, analisamos uma expressão de x+x++*x+*. Isso tem que ser x.
    • Agora tentamos analisar o mesmo operador,, +*+de +x++*x+*. No entanto, isso falha .
  • Então, voltamos atrás e tentamos analisar o operador +*.
    • Analisamos uma expressão de +x+x++*x+*. Como não começa x, precisamos analisar um operador.
    • A única possibilidade é +.
    • Agora analise uma subexpressão de x+x++*x+*. Isso tem que ser x.
    • Agora analise +novamente a partir de +x++*x+*.
    • Agora analise outra subexpressão de x++*x+*. Isso tem que ser x.
    • Finalmente, analise +novamente a partir de ++*x+*.
    • A expressão foi analisada com sucesso. Retornamos a string (x+x).
  • De volta ao nível de recursão anterior, analisamos o operador +*novamente a partir de +*x+*.
  • Agora analise outra subexpressão de x+*. Isso tem que ser x.
  • Finalmente, analise +*novamente a partir de +*.
  • A expressão foi analisada com sucesso. Retornamos a string ((x+x)+*x).

Como não restam mais caracteres, traduzimos a expressão com sucesso.

DLosc
fonte
4

Perl, 78 60 58 57 50 bytes

Inclui +1parap

Usa 1para +e 2para *(ou de fato qualquer dígito funciona para qualquer operador)

perl -pe 's/\b((\d+)((?1)|_)\2((?3))\2)\b/($3 $2 $4)/&&redo' <<< 22_22_22_2_2222_2

Para testes convenientes versus os exemplos fornecidos, você pode usar isso, que faz as traduções e a remoção de espaço para você:

perl -pe 'y/+*/12/;s/\b((\d+)((?1)|_)\2((?3))\2)\b/($3 $2 $4)/&&redo;y/ //d;y/12/+*/' <<< "**_**_**_*_****_*"
Ton Hospel
fonte
3

Limpo , 200 192 189 bytes

import StdEnv,Text
f"_"=["_"]
f l=["("+a+p+b+")"\\p<-[l%(0,i)\\i<-[0..indexOf"_"l]|endsWith(l%(0,i))l],t<-[tl(init(split p l))],n<-indexList t,a<-f(join p(take n t))&b<-f(join p(drop n t))]

Experimente online!

Define a função f, recebendo Stringe retornando um singleton [String]com o resultado dentro.

Algumas coisas legais:

  • Não usa regex
  • Funciona com qualquer caractere para operadores, exceto_
Furioso
fonte
3

Retina 0.8.2 , 138 bytes

.+
($&)
+`\((\d+)(_|((?<i>(?<i>\d+))|_(?<-i>\k<i>)+)+(?(i)(?!)))\1(_|((?<i>(?<i>\d+))|_(?<-i>\k<i>)+)+(?(i)(?!)))\1\)
(($2)$1($4))
\(_\)
_

Experimente online! O link inclui os casos de teste mais rápidos. Explicação: O mecanismo regex usa backtracking para dividir a sequência em tokens que são então pressionados ou ativados no igrupo de balanceamento. Sempre há uma execução de pelo menos um operador pressionado no início antes da primeira variável. Após uma variável, pelo menos um operador é acionado; nesse ponto, um operador pressionado ou outra variável é legal. Os operadores são empurrados para o grupo em duplicado, para que possam ser exibidos corretamente. Exemplo:

Input           Stack
Push *          * *
Push *++*+***   * * *++*+*** *++*+***
Push +          * * *++*+*** *++*+*** + +
Push +          * * *++*+*** *++*+*** + + + +
Variable _
Pop +           * * *++*+*** *++*+*** + + +
Variable _
Pop +           * * *++*+*** *++*+*** + +
Pop +           * * *++*+*** *++*+*** +
Variable _
Pop +           * * *++*+*** *++*+***
Pop *++*+***    * * *++*+***
Variable _
Pop *++*+***    * *
Pop *           *
Push *          * * *
Variable _
Pop *           * *
Push *          * * * *
Variable _
Pop *           * * *
Variable _
Pop *           * *
Pop *           *
Pop *

Infelizmente, isso não nos ajuda a capturar os resultados para agrupá-los, portanto o operador externo é correspondido manualmente. Os colchetes são adicionados de fora para dentro; portanto, o primeiro estágio agrupa toda a expressão entre colchetes e o último estágio os remove agora que eles se propagaram para as variáveis.

Neil
fonte
1
Isso também falha em **_**_**_*_****_*.
user202729
@ user202729 Trabalhando agora?
Neil
@ Neil Está funcionando agora, sim.
Οurous
1

Haskell , 167 166 bytes

head.e
e('_':r)=["_",r]
e(x:r)=[x]%r
e _=[]
o%t@(c:r)|[x,u]<-e t,n<-length o,[y,v]<-e$drop n u,all((==o).take n)[u,v]=['(':x++o++y++")",drop n v]|p<-o++[c]=p%r
o%_=[]

Experimente online! Exemplo de uso: head.e "**_**_**_*_****_*"rendimentos ((_*(_*(_*_)))*_). Todos os caracteres, exceto _são interpretados como operadores, _indicam um identificador.

Laikoni
fonte
0

Python 3, 226 bytes

from re import*
P=r'([*+]+)'+r'(\(.+?\)|_)\1'*2;R=lambda i,J=lambda i,o:i[:o]+sub(P,lambda o:'('+o[2]+o[1]+o[3]+')',i[o:],1),s=search:s(P,i)and R([J(i,o)for o in range(len(i))if s(P,J(i,o))or J(i,o)[0]+J(i,o)[-1]=='()'][0])or i

Define uma função anônima chamada R.

Experimente Online!

R. Kap
fonte
Observe que você pode usar qualquer caractere que não seja _*+; esses foram exatamente o que foram usados ​​no exemplo. Você pode usar isso para jogar golfe em suas regexes (por exemplo, usando em \dvez de [*+]).
Esolanging Fruit