Panoramica su infisso tra parentesi


16

Quylthulg è un linguaggio di Chris Pressey che tenta di risolvere il problema della notazione infografica usando quello che chiama panfix :

come postfix, panfix non richiede la distribuzione di congegni arcani come le parentesi per sovrascrivere una precedenza di operatore predefinita. Allo stesso tempo, panfix consente di specificare i termini nello stesso ordine e modo di infix, una notazione indiscutibilmente naturale e intuitiva per coloro che si sono abituati.


Come si ottiene la comodità della notazione infix insieme all'ambiguità di prefisso o postfisso? Usa tutti e tre, ovviamente!

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

Più formalmente, +siate un operatore ae bsiate espressioni. Quindi (a+b)è un'espressione infix valida (tra parentesi), la rappresentazione panfix di quell'espressione è +a+b+, dove giustapposizione rappresenta concatenazione.

Il tuo obiettivo è quello di prendere una stringa panfix e convertirla in infix completamente tra parentesi:

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

Per semplicità, apporteremo le seguenti modifiche:

  • Gli operatori possono consistere solo di due caratteri unici (puoi sceglierne uno qualsiasi, ma qui userò *e +).
  • C'è solo un letterale, che consiste in un altro personaggio distinto (puoi sceglierne uno qualsiasi, ma qui userò _).
  • L'input sarà un'espressione panfix ben formata.

Per complessità , apporteremo la seguente modifica:

  • Gli operatori possono essere composti da qualsiasi numero positivo di caratteri, non solo da uno.

Questo rende la sfida più complicata perché non è possibile determinare necessariamente come una determinata sottostringa di caratteri operatore sia partizionata senza guardare il resto della stringa.

Ecco un'implementazione di riferimento per la sfida, per gentile concessione di @ user202729.

Casi test

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

Ho usato questo programma per generare stringhe infix per questa sfida (la conversione in panfix era banale, ma non lo è l'inversione).




6
Banco di prova consigliato: **_**_**_*_****_*. Le risposte che ho testato hanno fallito tutte.
Nitrodon,

1
Posso avere spazi extra nel mio output, ad esempio (_ + _)?
Ton Hospel,

2
@TonHospel Certo.
Esolanging Fruit,

Risposte:


6

Prolog (SWI) , 194 163 byte

Hai salvato un enorme 31 byte usando questo suggerimento da 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-[].

L'operatore ^prende per l'argomento sinistro una stringa contenente un'espressione panfix e imposta il suo argomento destro su una stringa contenente l'espressione infix tra parentesi corrispondente. Usa xcome il letterale al posto di _.

Provalo online!

Spiegazione

Poiché Prolog è un linguaggio dichiarativo, non ci resta che descrivere la relazione tra un panfix e un'espressione tra parentesi.

La spiegazione usa questa versione leggermente non golfata:

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,[]).

La nostra produzione principale è parenthesize, che accetta un'espressione panfix Xcome stringa e invia l'espressione infix tra parentesi corrispondente Pcome stringa. Usa string_charsper convertire la stringa di input in un elenco di caratteri e poi semplicemente la passa a expr.

expraccetta un elenco di caratteri L, analizza la prima espressione di panfix in cui trova Le invia l'equivalente tra parentesi Xe il resto dell'elenco di caratteri R. Esistono due tipi possibili di espressioni:

  • Se il primo carattere di Lè x, allora l'espressione è xe il resto è tutto dopo x.
  • Altrimenti, analizza un operatore O(vedi opersotto); analizzare un'espressione Y; analizzare di Onuovo; analizzare un'altra espressione Z; e analizzare Ouna terza volta. Il resto è tutto dopo la terza istanza di O. L'espressione è il risultato di giunzione Y, Oe Z, circondato da parentesi, in una stringa.

opercontiene un elenco di personaggi, dove si trova il primo personaggio Ce gli altri sono T; analizza un operatore (ovvero una sequenza di uno o più caratteri operatore) e invia l'operatore Oe il resto dell'elenco di caratteri R. Per formare un operatore, il personaggio Cdeve essere diverso da x; anche

  • un operatore Pdeve essere analizzabile da T, con il resto R; in questo caso, Oè la concatenazione di Ce P; o,
  • Oè il singolo personaggio C; in questo caso, Rè giusto T.

Un esempio funzionante

Prendiamo l'input +*+x+x++*x+*per un esempio.

  • Vogliamo analizzare un'espressione da +*+x+x++*x+*. Questo non inizia con x, quindi analizziamo un operatore dall'inizio.
  • operanalizzerà il maggior numero possibile di operatori, quindi proviamo +*+.
    • Quindi analizziamo un'espressione da x+x++*x+*. Questo deve essere x.
    • Ora proviamo ad analizzare lo stesso operatore +*+, da +x++*x+*. Tuttavia, questo non riesce .
  • Quindi torniamo indietro e proviamo invece ad analizzare l'operatore +*.
    • Analizziamo un'espressione da +x+x++*x+*. Questo non inizia con x, quindi dobbiamo analizzare un operatore.
    • L'unica possibilità è +.
    • Ora analizza una sottoespressione da x+x++*x+*. Questo deve essere x.
    • Ora analizza di +nuovo da +x++*x+*.
    • Ora analizza un'altra sottoespressione da x++*x+*. Questo deve essere x.
    • Infine, analizzare di +nuovo da ++*x+*.
    • L'espressione è stata analizzata correttamente. Restituiamo la stringa (x+x).
  • Al livello di ricorsione precedente, analizziamo +*nuovamente l'operatore +*x+*.
  • Ora analizza un'altra sottoespressione da x+*. Questo deve essere x.
  • Infine, analizzare di +*nuovo da +*.
  • L'espressione è stata analizzata correttamente. Restituiamo la stringa ((x+x)+*x).

Poiché non ci sono più caratteri rimasti, abbiamo tradotto correttamente l'espressione.


4

Perl, 78 60 58 57 50 byte

Include +1perp

Utilizza 1per +e 2per *(o in effetti qualsiasi cifra funziona per qualsiasi operatore)

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

Per un comodo test rispetto agli esempi forniti, è possibile utilizzare ciò che esegue le traduzioni e la rimozione dello spazio per l'utente:

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

3

Pulito , 200 192 189 byte

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

Provalo online!

Definisce la funzione f, prendendo Stringe restituendo un singleton [String]con il risultato all'interno.

Alcune cose pulite:

  • Non usa regex
  • Funziona con qualsiasi personaggio per gli operatori tranne_

3

Retina 0.8.2 , 138 byte

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

Provalo online! Link include i casi di test più veloci. Spiegazione: Il motore regex utilizza il backtracking per dividere la stringa in token che vengono poi inseriti o estratti dal igruppo di bilanciamento. Esiste sempre almeno un operatore premuto all'inizio prima della prima variabile. Dopo una variabile, viene visualizzato almeno un operatore, a quel punto è legale un operatore spinto o un'altra variabile. Gli operatori vengono spinti nel gruppo in duplicato in modo che possano essere espulsi correttamente. Esempio:

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 *

Sfortunatamente questo non ci aiuta a catturare i risultati al fine di raggrupparli, quindi l'operatore esterno viene abbinato manualmente. Le parentesi vengono aggiunte all'esterno, quindi il primo stadio racchiude l'intera espressione tra parentesi e l'ultimo stadio li rimuove ora che si sono propagati fino alle variabili.


1
Anche questo fallisce **_**_**_*_****_*.
user202729,

@ user202729 Ora lavori?
Neil,

@Neil Ora funziona, sì.
6uroso

1

Haskell , 167 166 byte

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%_=[]

Provalo online! Esempio di utilizzo: head.e "**_**_**_*_****_*"rese ((_*(_*(_*_)))*_). Tutti i caratteri tranne quelli _sono interpretati come operatori, esso _stesso indica un identificatore.


0

Python 3, 226 byte

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

Definisce una funzione anonima denominata R.

Provalo online!


Nota che puoi usare qualsiasi carattere diverso da _*+; quelli erano proprio quelli usati nell'esempio. Potresti essere in grado di usarlo per giocare a golf con le tue regex (ad esempio usando \dinvece di [*+]).
Esolanging Fruit,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.