Parantez içine alınmış infix'e düzeltme


16

Quylthulg , Chris Pressey'nin panfix dediği şeyi kullanarak infix gösterimi sorununu çözmeye çalışan bir dildir :

postfix gibi, panfix de varsayılan operatör önceliğini geçersiz kılmak için parantez gibi gizli gizliliklerin konuşlandırılmasını gerektirmez. Aynı zamanda, panfix, terimlerin infix ile aynı sırada ve şekilde belirtilmesine izin verir, bu, alışmış olanlara tartışılmaz derecede doğal ve sezgisel bir gösterimdir.


Ön ek veya postfix'in belirsizliği ile birlikte infix gösteriminin rahatlığını nasıl elde edersiniz? Elbette üçünü de kullanın!

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

Daha resmi olarak, +bir operatör ave bifadeler olsun. Sonra (a+b)geçerli (parantez içine alınmış) bir infix ifadesidir, bu ifadenin panfix temsili +a+b+, burada yan yana yerleştirme birleşmeyi temsil eder.

Amacınız bir panfix dizesi alıp tam parantez içine alınmış infix'e dönüştürmektir:

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

Basit olması için aşağıdaki değişiklikleri yapacağız:

  • İşleçler yalnızca iki benzersiz karakterden oluşabilir (herhangi birini seçebilirsiniz, ancak burada *ve kullanacağım +).
  • Başka bir belirgin karakterden oluşan sadece bir değişmez var (herhangi birini seçebilirsiniz, ancak burada kullanacağım _).
  • Giriş, iyi biçimlendirilmiş bir panfix ifadesi olacaktır.

İçin karmaşıklığı , aşağıdaki değişiklik yapacağız:

  • İşleçler yalnızca bir karakterden değil , herhangi bir pozitif karakterden oluşabilir .

Bu, zorluğu daha zor hale getirir, çünkü belirli bir operatör karakter alt dizesinin dizenin geri kalanına bakmadan nasıl bölümlendiğini belirleyemezsiniz.

İşte @ user202729'un izniyle meydan okuma için bir referans uygulaması .

Test Durumları

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

Bu meydan okuma için infix dizeleri oluşturmak için bu programı kullandım (panfix dönüştürmek önemsiz, ama ters değil).




6
Önerilen test durumu: **_**_**_*_****_*. Test ettiğim cevapların hepsi başarısız oldu.
Nitrodon

1
Çıktımda fazladan boşluk olabilir (_ + _)mi , örneğin ?
Ton Hospel

2
@TonHospel Tabii.
Esolanging Fruit

Yanıtlar:


6

Prolog (SWI) , 194 163 bayt

0 ' dan bu ipucunu kullanarak 31 bayt kaydetti !

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

Operatör ^sol argümanı için bir panfix ifadesi içeren bir dize alır ve sağ bağımsız değişkenini karşılık gelen parantez içine alınmış infix ifadesini içeren bir dizeye ayarlar. xYerine değişmez olarak kullanır _.

Çevrimiçi deneyin!

açıklama

Prolog bildirici bir dil olduğundan, bir panfix ve parantez içine alınmış ifade arasındaki ilişkiyi tanımlamamız yeterlidir.

Açıklama, bu hafifçe çözülmemiş sürümü kullanır:

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

Ana üretimimiz parenthesizepanfix ifadesini Xdize olarak alır ve karşılık gelen parantez içine alınmış infix ifadesini Pdize olarak gönderir . string_charsGiriş dizesini bir karakter listesine dönüştürmek için kullanır ve daha sonra üzerine geçirir expr.

exprkarakter listesini alır, Lbulduğu ilk panfix ifadesini ayrıştırır Lve parantez içindeki eşdeğerini Xve karakter listesinin geri kalanını gönderir R. İki olası ifade türü vardır:

  • Eğer ilk karakteri Lise x, o zaman ifade olur xve geri kalan ise x.
  • Aksi takdirde bir operatörü ayrıştırın O(aşağıya operbakın); bir ifadeyi ayrıştırma Y; Otekrar ayrıştırma ; başka bir ifadeyi ayrıştırma Z; ve Oüçüncü kez ayrıştırın . Kalan kısım ise üçüncü örneğinden sonraki her şeydir O. İfadesi katılmadan sonucudur Y, Ove Zbir dizeye, parantez çevrili.

operilk karakterin Cve geri kalanı olan karakterlerin bir listesini alır T; bir işleci ayrıştırır (yani bir veya daha fazla işleç karakteri çalışması) ve işleci Ove karakter listesinin geri kalanını gönderir R. Bir operatör oluşturmak için, karakter Cbaşka bir şey olmalı x; ayrıca, ya

  • bir operatörün geri kalanıyla Payrıştırılabilir olması gerekir ; bu durumda, birleşimi ve ; veya,TROCP
  • Otek karakterdir C; bu durumda, Rsadece T.

Çalışan bir örnek

+*+x+x++*x+*Bir örnek için girdiyi ele alalım.

  • Bir ifadeyi ayrıştırmak istiyoruz +*+x+x++*x+*. Bu ile başlamıyor x, bu yüzden bir operatörü baştan ayrıştırıyoruz.
  • opermümkün olduğunca büyük bir operatör ayrıştıracaktır, bu yüzden deniyoruz +*+.
    • Sonra bir ifade ayrıştırıyoruz x+x++*x+*. Bu olmalı x.
    • Şimdi, aynı operatöre ayrıştırmak deneyin +*+gelen +x++*x+*. Ancak, bu başarısız olur .
  • Bu yüzden operatörü geri takip edip ayrıştırmayı deniyoruz +*.
    • Bizden bir ifade ayrıştırıyoruz +x+x++*x+*. Bu başlamıyor x, bu yüzden bir operatörü ayrıştırmamız gerekiyor.
    • Tek olasılık +.
    • Şimdi bir alt ifadeyi ayrıştırın x+x++*x+*. Bu olmalı x.
    • Şimdi +tekrar ayrıştır +x++*x+*.
    • Şimdi başka bir alt ifadeyi ayrıştırın x++*x+*. Bu olmalı x.
    • Son olarak, +tekrar ayrıştırın ++*x+*.
    • İfade başarıyla ayrıştırıldı. Dizeyi döndürüyoruz (x+x).
  • Önceki özyineleme düzeyinde, operatörü +*tekrar ayrıştırıyoruz +*x+*.
  • Şimdi başka bir alt ifadeyi ayrıştırın x+*. Bu olmalı x.
  • Son olarak, +*tekrar ayrıştırın +*.
  • İfade başarıyla ayrıştırıldı. Dizeyi döndürüyoruz ((x+x)+*x).

Başka karakter kalmadığından, ifadeyi başarıyla tercüme ettik.


4

Perl, 78 60 58 57 50 bayt

içerir +1içinp

Kullanımları 1için +ve 2için *(veya aslında herhangi operatör için herhangi haneli işleri)

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

Verilen örneklere karşı uygun testler için, çevirileri ve alan kaldırma işlemlerini sizin yerinize yapabilirsiniz:

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

3

Temiz , 200 192 189 bayt

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

Çevrimiçi deneyin!

İçerideki sonuçla birlikte bir tekton işlevi f, alma Stringve döndürme işlevini tanımlar [String].

Bazı düzgün şeyler:

  • Normal ifade kullanmaz
  • Operatörler için herhangi bir karakter ile çalışır hariç_

3

Retina 0.8.2 , 138 bayt

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

Çevrimiçi deneyin! Bağlantı daha hızlı test senaryolarını içerir. Açıklama: Normal ifade motoru, dizeyi daha sonra idengeleme grubuna aktarılan veya bu gruptan atılan belirteçlere bölmek için geri izleme kullanır . Başlangıçta her zaman ilk değişkenin önünde itilen en az bir operatörün çalışması vardır. Bir değişkenden sonra, en az bir işleç açılır; bu noktada, itilmiş bir işleç çalışması veya başka bir değişken yasaldır. İşleçler, doğru bir şekilde atanabilmeleri için gruba çift olarak aktarılır. Misal:

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 *

Maalesef bu, sonuçları desteklemek için sonuçları yakalamamıza yardımcı olmaz, bu nedenle dış operatör manuel olarak eşleştirilir. Köşeli parantezler dışarıya eklenir, böylece ilk aşama tüm ifadeyi parantez içine alır ve son aşama, değişkenlere yayıldıkları için bunları kaldırır.


1
Bu da başarısız olur **_**_**_*_****_*.
user202729

@ user202729 Şimdi mi çalışıyorsunuz?
Neil

@Neil Şimdi çalışıyor, evet.
18'de

1

Haskell , 167 166 bayt

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

Çevrimiçi deneyin! Örnek kullanım: head.e "**_**_**_*_****_*"verim ((_*(_*(_*_)))*_). Dışındaki tüm karakterler _operatör olarak yorumlanır, _kendisi bir tanımlayıcı gösterir.


0

Python 3, 226 bayt

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

Adında anonim bir işlev tanımlar R.

Çevrimiçi deneyin!


Eğer dışında herhangi bir karakter kullanabileceğinizi unutmayın _*+; bunlar sadece örnekte kullanılanlardı. Normal ifadelerinizi golf için kullanabilirsiniz (örneğin \dyerine [*+]).
Esolanging Fruit
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.