Ketika saya melihat judul pertanyaan tertutup ini , saya pikir itu tampak seperti tantangan kode golf yang menarik. Jadi izinkan saya menyajikannya sebagai berikut:
Tantangan:
Tulis sebuah program, ekspresi atau subrutin yang, diberi ekspresi aritmetika dalam notasi infiks , seperti 1 + 2
, menghasilkan ekspresi yang sama dalam notasi postfix , yaitu 1 2 +
.
(Catatan: Tantangan serupa telah diposting sebelumnya pada bulan Januari. Namun, saya merasa kedua tugas tersebut cukup berbeda secara detail untuk membenarkan tantangan terpisah ini. Juga, saya hanya melihat utas lainnya setelah mengetik semua yang di bawah ini, dan saya lebih suka tidak hanya membuang semuanya.)
Memasukkan:
Input terdiri dari infix ekspresi aritmatika yang valid terdiri dari angka (bilangan bulat non-negatif direpresentasikan sebagai urutan satu atau lebih desimal digit), seimbang kurung untuk menunjukkan subexpression dikelompokkan, dan empat infiks biner operator +
, -
, *
dan /
. Semua ini dapat dipisahkan (dan seluruh ekspresi dikelilingi) oleh sejumlah karakter spasi, yang harus diabaikan. 1
Bagi mereka yang menyukai tata bahasa formal, inilah tata bahasa sederhana seperti BNF yang mendefinisikan input yang valid. Untuk singkatnya dan kejelasan, tata bahasa tidak termasuk spasi opsional, yang dapat terjadi antara dua token (selain dari digit dalam angka):
expression := number | subexpression | expression operator expression
subexpression := "(" expression ")"
operator := "+" | "-" | "*" | "/"
number := digit | digit number
digit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
1 Satu-satunya kasus di mana keberadaan spasi dapat mempengaruhi penguraian adalah ketika mereka memisahkan dua angka berurutan; Namun, karena dua angka yang tidak dipisahkan oleh operator tidak dapat terjadi dalam ekspresi infiks yang valid, kasus ini tidak akan pernah terjadi pada input yang valid.
Keluaran:
Outputnya harus berupa ekspresi postfix yang setara dengan input. Ekspresi output hanya boleh terdiri dari angka dan operator, dengan karakter spasi tunggal antara setiap pasangan token yang berdekatan, seperti dalam tata bahasa berikut (yang tidak termasuk spasi) 2 :
expression := number | expression sp expression sp operator
operator := "+" | "-" | "*" | "/"
number := digit | digit number
digit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
sp := " "
2 Sekali lagi untuk kesederhanaan, number
produksi dalam tata bahasa ini mengakui angka dengan nol di depan, meskipun mereka dilarang dalam output oleh aturan di bawah ini.
Diutamakan operator:
Dengan tidak adanya tanda kurung, aturan diutamakan berikut ini berlaku:
- Operator
*
dan/
memiliki prioritas lebih tinggi daripada+
dan-
. - Operator
*
dan/
memiliki prioritas yang sama satu sama lain. - Operator
+
dan-
memiliki prioritas yang sama satu sama lain. - Semua operator bersifat asosiatif kiri.
Misalnya, dua ekspresi berikut ini setara:
1 + 2 / 3 * 4 - 5 + 6 * 7
((1 + ((2 / 3) * 4)) - 5) + (6 * 7)
dan keduanya harus menghasilkan output berikut:
1 2 3 / 4 * + 5 - 6 7 * +
(Ini adalah aturan presedensi yang sama seperti dalam bahasa C dan dalam sebagian besar bahasa yang berasal darinya. Mereka mungkin menyerupai aturan yang diajarkan pada Anda di sekolah dasar, kecuali mungkin untuk diutamakan relatif dari *
dan /
.)
Aturan lain-lain:
Jika solusi yang diberikan adalah ekspresi atau subrutin, input harus diberikan dan output dikembalikan sebagai string tunggal. Jika solusinya adalah program yang lengkap, ia harus membaca baris yang berisi ekspresi infiks dari input standar dan mencetak baris yang berisi versi postfix ke output standar.
Angka dalam input mungkin termasuk nol di depan. Angka dalam output tidak boleh memiliki nol di depannya (kecuali untuk angka 0, yang akan menjadi output sebagai
0
).Anda tidak diharapkan untuk mengevaluasi atau mengoptimalkan ekspresi dengan cara apa pun. Secara khusus, Anda tidak boleh berasumsi bahwa operator harus memenuhi identitas aljabar, komutatif, atau lainnya. Artinya, Anda tidak boleh berasumsi bahwa eg
1 + 2
sama dengan2 + 1
atau1 + (2 + 3)
sama dengan itu(1 + 2) + 3
.Anda dapat berasumsi bahwa angka dalam input tidak melebihi 2 31 - 1 = 2147483647.
Aturan-aturan ini dimaksudkan untuk memastikan bahwa output yang benar didefinisikan secara unik oleh input.
Contoh:
Berikut adalah beberapa ekspresi input yang valid dan output yang sesuai, yang disajikan dalam formulir "input" -> "output"
:
"1" -> "1"
"1 + 2" -> "1 2 +"
" 001 + 02 " -> "1 2 +"
"(((((1))) + (2)))" -> "1 2 +"
"1+2" -> "1 2 +"
"1 + 2 + 3" -> "1 2 + 3 +"
"1 + (2 + 3)" -> "1 2 3 + +"
"1 + 2 * 3" -> "1 2 3 * +"
"1 / 2 * 3" -> "1 2 / 3 *"
"0102 + 0000" -> "102 0 +"
"0-1+(2-3)*4-5*(6-(7+8)/9+10)" -> "0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -"
(Setidaknya, saya harap semua ini benar; Saya melakukan pertobatan dengan tangan, sehingga kesalahan mungkin merayap masuk.)
Supaya jelas, input berikut semuanya tidak valid; itu tidak peduli apa solusi Anda tidak jika diberikan mereka (meskipun, tentu saja, misalnya kembali pesan kesalahan lebih bagus daripada, katakanlah, mengkonsumsi jumlah tak terbatas memori):
""
"x"
"1 2"
"1 + + 2"
"-1"
"3.141592653589793"
"10,000,000,001"
"(1 + 2"
"(1 + 2)) * (3 / (4)"
1 2 3 4 +
berarti `1 + 2 + 3 + 4`.1 2 3 4 + *
?Jawaban:
Utilitas shell - 60 karakter
Memperbaiki berbagai masalah, tapi itu menjadi lebih lama :(
sumber
sed -re's/[:@iKWr]+/ /g'
perbaiki dengan biaya 1 karakter.C,
250245236193185 karakterIni adalah versi yang dapat dibaca dari sumber yang tidak dikenali, yang masih mencerminkan logika dasar. Ini sebenarnya program yang agak mudah. Satu-satunya pekerjaan nyata yang harus dilakukan adalah untuk mendorong operator asosiasi rendah ke tumpukan ketika operator asosiasi tinggi ditemukan, dan kemudian pop kembali di "ujung" dari subekspresi itu.
sumber
if
. Misalnyaif(!*p||*p==41)return p;s[++t]=*p;}
->return*p&&*p-41?s[++t]=*p:p;
*f(p,s)char*p,s;{
if
tes gagal. 2. Saya tahu, tetapi deklarasi fungsi K&R adalah tempat saya menggambar garis. Aku tidak bisa kembali ke mereka.}}
danfor
. Tapi berikut ini adalah persetujuan:printf(" %ld"+!a,...
p
global (panggilan rekursif hanya menetapkan calleep
kembali ke penelepon). Lalu lakukanf(p=gets(b))
.Bash dengan Haskell dengan
C preprocessorsed, 180195198275Akhirnya, ini tidak lebih lama dari solusi C lagi. Bagian penting Haskell hampir sama malasnya dengan solusi bc ...
Mengambil input sebagai parameter baris perintah. File
w
dengan beberapa pesan peringatan ghc akan dibuat, jika Anda tidak suka perubahan inirunghc 2>/dev/null
.sumber
Python 2,
290272268250243238 byteSekarang akhirnya lebih pendek dari jawaban JS!
Ini adalah program lengkap yang menggunakan implementasi dasar dari algoritma shunting yard . Input diberikan sebagai string yang dikutip, dan hasilnya dicetak ke
STDOUT
.Cobalah online!
Penjelasan:
Hal pertama yang perlu kita lakukan adalah mengubah input menjadi token. Kami melakukan ini dengan menggunakan semua kecocokan dari regex
\d+|\S
, yang diterjemahkan secara kasar ke "grup digit apa pun, dan karakter apa pun yang bukan spasi". Ini menghapus spasi putih, mem-parsing digit yang berdekatan sebagai token tunggal, dan mem-parsing operator secara terpisah.Untuk algoritma halaman shunting, ada 4 jenis token berbeda yang perlu kita tangani:
(
- Kurung kiri)
- Tanda kurung tepat+-*/
- Operator9876543210
- Numerik literalUntungnya, kode ASCII ini semuanya dikelompokkan dalam urutan yang ditunjukkan, sehingga kita dapat menggunakan ekspresi
(t>'/')+(t>')')+(t>'(')
untuk menghitung jenis token. Ini menghasilkan 3 untuk digit, 2 untuk operator, 1 untuk tanda kurung kanan dan 0 untuk tanda kurung kiri.Dengan menggunakan nilai-nilai ini, kami mengindeks ke tuple besar setelah
exec
untuk mendapatkan potongan yang sesuai untuk dieksekusi, berdasarkan pada jenis token. Ini berbeda untuk setiap token dan merupakan tulang punggung dari algoritma halaman shunting. Dua daftar digunakan (sebagai tumpukan):O
(tumpukan operasi) danB
(buffer output). Setelah semua token dijalankan, operator yang tersisa padaO
stack disatukan dengan buffer output, dan hasilnya dicetak.sumber
Prolog (SWI-Prolog) , 113 byte
Cobalah online!
Prolog SWI memiliki set builtin yang jauh lebih baik untuk ini daripada Prolog GNU, tetapi itu masih agak terbendung oleh verbositas sintaks Prolog.
Penjelasan
term_to_atom
akan, jika dijalankan mundur, mem-parse ekspresi infiks-notasi (disimpan sebagai atom) menjadi pohon parse (mematuhi aturan prioritas yang biasa, dan menghapus angka nol dan spasi yang memimpin). Kami kemudian menggunakan predikat helperc
untuk melakukan rekursi struktural di atas pohon parse, yang diubah menjadi notasi postfix dengan cara yang lebih dulu mendalam.sumber
Javascript (ES6), 244 byte
Contoh:
Panggilan:
f('0-1+(2-3)*4-5*(6-(7+8)/9+10)')
Keluaran:
0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -
(dengan spasi tambahan)Penjelasan:
sumber
R, 142 byte
R dapat menguraikan sendiri, jadi daripada menemukan kembali roda, kami hanya menempatkan pengurai untuk bekerja, yang menghasilkan notasi awalan, dan menggunakan fungsi rekursif untuk mengubahnya ke notasi postfix.
The
p
argumen adalah untuk mengontrol penggunaan evaluasi non-standar (kutukan programmer R di mana-mana), dan ada beberapa tambahanif
dalam sana untuk mengontrol keluaran kurung (yang kita ingin menghindari).Memasukkan:
(0-1+(2-3)*4-5*(6-(7+8)/9+10))
Keluaran:
0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -
Memasukkan:
(((((1))) + (2)))
Keluaran:
1 2 +
Sebagai bonus, ia bekerja dengan simbol sewenang-wenang, dan fungsi yang telah ditentukan sebelumnya hingga dua argumen:
Identitas Euler
Memasukkan:
e^(i*pi)-1
Keluaran:
e i pi * ^ 1 -
Dividen 13 antara 1 dan 100
Memasukkan:
which(1:100 %% 13 == 0)
Keluaran:
1 100 : 13 %% 0 == which
Regresi linier berat bayi ayam sebagai fungsi waktu
Memasukkan:
summary(lm(weight~Time, data=ChickWeight))
Keluaran:
weight Time ~ ChickWeight lm summary
Contoh terakhir mungkin sedikit di luar ruang lingkup OP, tetapi menggunakan notasi postfix, jadi ...
sumber