Parsing string Python literal

9

Tantangannya adalah mengurai string seperti yang dilakukan Python dan mencetak isi string.

  • Input (argumen baris perintah atau stdin) : string literal (misalnya "hello") (atau beberapa literal, lihat rangkaian literal string di bawah)
  • Output (stdout) : isi string (misalnya hello)

Aturan untuk mengurai string:

  • Sebuah string literal dilampirkan dalam pasangan yang cocok dari tanda kutip tunggal ( 'a'), tanda kutip ganda ( "a"), tanda kutip tunggal tiga ( '''a''') atau tanda kutip ganda ganda ( """a"""). Pengulangan pertama dari jenis kutipan yang membuka string mengakhiri string.
  • Backslash lolos: \' dalam string menjadi ', \"menjadi "dan \\menjadi \. Anda tidak perlu menerapkan lolos backslash lainnya. Garis miring terbalik yang bukan bagian dari urutan pelarian tetap merupakan garis miring terbalik.
  • Rangkaian literal string: Isi literal string yang berdekatan digabungkan. Misalnya, "hello" 'world'menjadi helloworld.
  • Masukan mungkin berisi spasi yang bukan bagian dari literal apa pun.
  • Anda tidak perlu mendukung jenis ruang putih apa pun, baik di dalam maupun di luar literal.

Aturan tambahan:

  • eval, execdan hal serupa tidak diperbolehkan untuk menguraikan literal atau bagian dari itu.
  • Anda dapat berasumsi bahwa input tersebut valid.
  • Anda dapat mengasumsikan panjang input maksimum 1023 karakter.

Contoh:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (tanpa tanda kurung, tetapi dengan spasi) -> """'''

Kode terpendek menang.

gempa bumi
sumber
Apakah hasilnya berupa bentuk yang dapat disimpan, atau apakah cukup untuk mencetaknya dan dikerjakan?
DavidC
@ David Mencetak itu semua yang perlu Anda lakukan.
flornquake
Jadi di (misal) "\ z", kode tersebut secara khusus diperlukan untuk menampilkan backslash dan z? Tapi 'menjadi hanya tanda kutip, bahkan jika itu muncul di dalam tanda kutip ganda atau tanda kutip tiga? Apakah itu benar?
kotak roti
@breadbox Tepat.
flornquake
Haruskah kode mendukung string mentah? Dan bagaimana dengan rangkaian string non-mentah dan mentah?
Bakuriu

Jawaban:

4

Perl, 54 karakter

#!/usr/bin/perl -p
s/ |("""|'''|"|')((\\?.)*?)\1/$2/g;s/\\(["'\\])/$1/g

Tepat ketika saya memposting ini, saya perhatikan bahwa itu hampir identik dengan solusi Ruby Jan Dvorak. Saya sedikit kecewa dengan betapa miripnya itu, pada kenyataannya, tetapi saya akan mengatakan "Orang-orang hebat berpikiran sama" dan biarkan begitu saja.

Program ini menyoroti kasus sudut aneh dalam menghitung karakter dalam skrip Perl: Dengan membaca saya, kehadiran tanda kutip tunggal dalam skrip berarti bahwa saya perlu menghitung -popsi sebagai dua karakter terhadap total saya. Biasanya, saat menghitung ukuran skrip Perl, karakter awal dasbor pada opsi dianggap gratis, dengan justifikasi bahwa ia dapat digabungkan dengan -eyang memperkenalkan program dengan benar ... tetapi kemudian Anda juga harus memperhitungkan setiap pelarian tambahan Anda harus memasukkan skrip pada baris perintah. Kutipan tunggal membutuhkan banyak pelarian, jadi untuk menghindari hukuman itu saya harus menghitungnya sebagai skrip dijalankan dari file, dan karena itu saya mendapatkan #!/usr/bin/perlsecara gratis, tetapi tidak ada karakter opsi. Agak membingungkan.

kotak roti
sumber
2
Jika Anda ingin tampil beda, (('|")\2{2}?)panjangnya sama dengan("""|'''|"|')
Peter Taylor
3

C, 178 karakter

char*p,*q,b[1024];d;main(t){for(p=q=gets(b);*p=*q++;)
d?*p==92&!(*q-*p&&*q-34&&*q-39)?*p++=*q++:*p-d||t&&*q-d|q[1]-d?++p:
(d=0,q+=2*t):*p-32?d=*p,t=*q==d&q[1]==d,q+=2*t:0;puts(b);}

Ini adalah salah satu solusi C di mana semuanya dilakukan di dalam geng rantai operator ternary.

Program ini bekerja dengan menyalin kembali karakter ke buffer yang sama, menimpa karakter metak. dmemegang pembatas ketika di dalam string, dan tbenar jika pembatas adalah kuotasi tiga.

kotak roti
sumber
Saya pikir Anda perlu menyertakan tambahan tambahan bersyarat dari variabel kontrol loop. Untuk 'foo \\' bar 'ia memberikan foo \ ar', yang sepertinya menggantikan \\ dengan \, tetapi kemudian melanjutkan parsing dengan yang baru dimasukkan \, melihat token berikutnya sebagai \ '.
manatwork
Sebenarnya, contoh itu adalah input yang tidak valid. 'foo\\'merujuk ke string foo \, yang kemudian diikuti oleh karakter yang bukan spasi putih atau pembatas string.
kotak roti
Ups. Saya salah membaca aturan itu. Maka tentu saja kode Anda benar.
manatwork
3

Rubi, 74 73 karakter

puts gets.gsub(/('''|"""|'|")((\\?.)*?)\1|./,'\2').gsub /\\([\\'"])/,'\1'

Inti di sini adalah dua regex: Yang pertama menentukan batas string dan memilih konten saja. Perubahan ada untuk menghapus semua yang tidak ada di dalam string, dan juga menjatuhkan string yang tidak tertutup.Serangan balik diperlakukan sebagai possesif-opsional diikuti oleh apa pun. Jadi,Karena mesin regex tidak akan mundur ke (\\?.)input yang valid (terima kasih @breadbox), satu backslash tidak dapat cocok di sana. Kutipan ditangani melalui pengulangan malas. Regex kedua kemudian strip backslash sebelum masing-masing karakter dapat melarikan diri. Regex tergantung pada mesin untuk selalu memilih alternatif paling kiri terlebih dahulu.

Saya juga mempertimbangkan pendekatan state-machine, tetapi ternyata cukup besar (19 status x 4 kelas karakter) dibandingkan dengan solusi regex. Saya masih dapat memposting mesin negara jika ada yang tertarik.

John Dvorak
sumber
Satu kesalahan kecil dengan metode ini: 'foo \\' bar 'menjadi foo \ daripada' foo \ 'bar'.
manatwork
@manatwork ini benar, kecuali ada sesuatu yang hilang dalam format. Backslash pertama lolos dari yang kedua. 'foo\\'adalah string pertama dan bar'berada di luar konteks string ketika inputnya adalah'foo\\'bar'
John Dvorak
Ups. Tidak tahu bagaimana saya menghitungnya sebelumnya. Tentu saja itu benar. Maaf.
manatwork
Ketika saya mencoba menjalankan ini, saya mendapatkan pesan kesalahan: "nested *? + In regexp". Apakah ada versi minimum atau flag runtime yang saya butuhkan?
kotak roti
@breadbox Saya belum memeriksa versi lain, tapi saya menjalankan ruby ​​1.9.3 (JRuby 1.7.2). haruskah saya berasumsi paling tidak 1.9.3 dan mengeditnya?
John Dvorak