Saya mencoba mencari solusi yang lebih baik untuk membuat parser ke beberapa format file terkenal di luar sana seperti: EDIFACT dan TRADACOMS .
Jika Anda tidak terbiasa dengan standar ini maka lihat contoh ini dari Wikipedia:
Lihat di bawah untuk contoh pesan EDIFACT yang digunakan untuk menjawab permintaan ketersediaan produk: -
UNA:+.? '
UNB+IATB:1+6XPPC+LHPPC+940101:0950+1'
UNH+1+PAORES:93:1:IA'
MSG+1:45'
IFT+3+XYZCOMPANY AVAILABILITY'
ERC+A7V:1:AMD'
IFT+3+NO MORE FLIGHTS'
ODI'
TVL+240493:1000::1220+FRA+JFK+DL+400+C'
PDI++C:3+Y::3+F::1'
APD+714C:0:::6++++++6X'
TVL+240493:1740::2030+JFK+MIA+DL+081+C'
PDI++C:4'
APD+EM2:0:130::6+++++++DA'
UNT+13+1'
UNZ+1+1'
Segmen UNA adalah opsional. Jika ada, itu menentukan karakter khusus yang akan digunakan untuk menafsirkan sisa pesan. Ada enam karakter yang mengikuti UNA dalam urutan ini:
- pemisah elemen data komponen (: dalam sampel ini)
- pemisah elemen data (+ dalam sampel ini)
- pemberitahuan desimal (. dalam sampel ini)
- rilis karakter (? dalam sampel ini)
- dipesan, harus spasi
- terminator segmen ('dalam sampel ini)
Seperti yang Anda lihat itu hanya beberapa data yang diformat dengan cara khusus menunggu untuk diuraikan (seperti file XML ).
Sekarang sistem saya dibangun di PHP dan saya bisa membuat parser menggunakan ekspresi reguler untuk setiap segmen, tetapi masalahnya tidak semua orang mengimplementasikan standar dengan sempurna.
Beberapa pemasok cenderung mengabaikan segmen dan bidang opsional sepenuhnya. Orang lain mungkin memilih untuk mengirim lebih banyak data daripada yang lain. Itu sebabnya saya terpaksa membuat validator untuk segmen dan bidang untuk menguji apakah file itu benar atau tidak.
Anda dapat membayangkan mimpi buruk ekspresi reguler yang saya alami sekarang. Selain itu setiap pemasok membutuhkan banyak modifikasi pada ekspresi reguler yang saya cenderung buat parser untuk setiap pemasok.
Pertanyaan:
1- Apakah ini praktik terbaik untuk mem-parsing file (menggunakan ekspresi reguler)?
2- Apakah ada solusi yang lebih baik untuk mem-parsing file (mungkin ada solusi yang sudah jadi di luar sana)? Apakah dapat menampilkan segmen apa yang hilang atau jika file rusak?
3 - Jika saya harus membuat parser saya, pola atau metodologi desain apa yang harus saya gunakan?
Catatan:
Saya membaca di suatu tempat tentang yacc dan ANTLR, tetapi saya tidak tahu apakah mereka cocok dengan kebutuhan saya atau tidak!
sumber
Jawaban:
Yang Anda butuhkan adalah parser sejati. Ekspresi reguler menangani lexing, bukan parsing. Yaitu, mereka mengidentifikasi token dalam aliran input Anda. Parsing adalah konteks token, yaitu IE yang pergi ke mana dan dalam urutan apa.
Alat parsing klasik adalah yacc / bison . Lexer klasik adalah lex / flex . Karena php memungkinkan untuk mengintegrasikan kode C , Anda dapat menggunakan flex dan bison untuk membangun parser Anda, minta php menyebutnya pada file input / stream, dan kemudian dapatkan hasilnya.
Ini akan sangat cepat , dan jauh lebih mudah untuk dikerjakan setelah Anda memahami alat-alatnya . Saya sarankan membaca Lex dan Yacc 2nd Ed. dari O'Reilly. Sebagai contoh, saya telah membuat proyek flex dan bison di github , dengan makefile. Dapat dikompilasi silang untuk windows jika perlu.
Ini adalah kompleks, tetapi karena Anda tahu, apa yang Anda perlu lakukan adalah kompleks. Ada banyak "hal" yang harus dilakukan untuk parser yang berfungsi dengan baik, dan flex dan bison berurusan dengan bit mekanik. Jika tidak, Anda menemukan diri Anda dalam posisi yang tidak diinginkan dari penulisan kode pada lapisan abstraksi yang sama dengan perakitan.
sumber
Aduh .. pengurai 'benar'? mesin negara ??
maaf tapi saya sudah dikonversi dari akademik ke hacker sejak saya mulai pekerjaan saya .. jadi saya akan mengatakan ada cara yang lebih mudah .. walaupun mungkin tidak 'halus' secara akademis :)
Saya akan mencoba menawarkan pendekatan alternatif yang beberapa mungkin setuju atau tidak setuju tetapi itu BISA sangat praktis dalam lingkungan kerja.
Saya akan;
dari sana saya akan menggunakan kelas untuk tipe data. memisahkan komponen dan elemen pemisah dan beralih ke array yang dikembalikan.
Bagi saya, ini adalah penggunaan kembali kode, OO, kohesi rendah dan sangat modular .. dan mudah untuk debug dan program. lebih sederhana lebih baik.
untuk mem-parsing file Anda tidak perlu mesin negara atau sesuatu yang sepenuhnya rumit .. mesin negara sangat cocok untuk mengurai kode, Anda akan terkejut melihat betapa kuatnya kode pseduo di atas dapat ketika digunakan dalam konteks OO.
ps. Saya telah bekerja dengan file yang sangat mirip sebelumnya :)
Lebih banyak kode semu yang diposting di sini:
kelas
Anda bisa menggunakannya seperti ini ..
dan katakan Anda memiliki lebih dari satu segmen .. gunakan antrian untuk menambahkannya dan dapatkan yang pertama, kedua dll. sesuai kebutuhan. Anda benar-benar hanya mewakili pesan ke objek dan memberikan metode objek untuk memanggil data. Anda dapat mengambil keuntungan dari ini dengan juga menciptakan metode khusus .. untuk warisan .. baik itu pertanyaan yang berbeda dan saya pikir Anda dapat dengan mudah menerapkannya jika Anda memahaminya
sumber
recognize X token and do Y
. Tidak ada konteks, Anda tidak dapat memiliki banyak status, melewati beberapa kasus sepele kode, dan penanganan kesalahan sulit. Saya menemukan bahwa saya membutuhkan fitur-fitur ini di dunia nyata di hampir semua kasus. Itu meninggalkan kesalahan di dalamnya sebagai kompleksitas tumbuh. Bagian tersulit adalah menyiapkan kerangka, dan mempelajari cara alat beroperasi. Lewati itu dan cepat untuk menyiapkan sesuatu.parseUNAsegemntForVendor1()
,parseUNAsegemntForVendor2()
,parseUNAsegemntForVendor3()
, ... dll), kan?Sudahkah Anda mencoba googling untuk "PHP EDIFACT"? Ini adalah salah satu hasil pertama yang muncul: http://code.google.com/p/edieasy/
Meskipun mungkin tidak cukup untuk kasus penggunaan Anda, Anda mungkin bisa mendapatkan beberapa ide darinya. Saya tidak suka kode dengan banyak bersarang untuk loop dan kondisi, tetapi ini mungkin permulaan.
sumber
Yah sejak Yacc / Bison + Flex / Lex disebutkan, saya mungkin juga memasukkan salah satu alternatif utama lainnya: parser combinators. Ini populer di pemrograman fungsional seperti dengan Haskell, tetapi jika Anda dapat antarmuka ke kode C Anda dapat menggunakannya dan, apa yang Anda tahu, seseorang menulis satu untuk PHP juga. (Saya tidak punya pengalaman dengan implementasi khusus itu, tetapi jika berfungsi seperti kebanyakan dari mereka, itu pasti cukup bagus.)
Konsep umum adalah bahwa Anda mulai dengan seperangkat parser kecil, mudah didefinisikan, biasanya tokenizer. Seperti Anda akan memiliki satu fungsi pengurai untuk masing-masing dari 6 elemen data yang Anda sebutkan. Kemudian Anda menggunakan kombinator (fungsi yang menggabungkan fungsi) untuk membuat parser yang lebih besar yang mengambil elemen yang lebih besar. Seperti segmen opsional akan menjadi
optional
kombinator yang beroperasi pada pengurai segmen.Tidak yakin seberapa baik kerjanya dalam PHP, tapi ini cara yang menyenangkan untuk menulis parser dan saya sangat menikmati menggunakannya dalam bahasa lain.
sumber
alih-alih mengutak-atik regex membuat mesin negara Anda sendiri
ini akan lebih mudah dibaca (dan dapat memiliki komentar yang lebih baik) dalam situasi non-sepele dan akan lebih mudah untuk debug bahwa kotak hitam yang regex
sumber
Saya tidak tahu apa yang ingin Anda lakukan dengan data ini setelahnya dan jika itu bukan godam untuk kacang, tapi saya punya pengalaman bagus dengan eli . Anda menggambarkan frasa leksikal dan kemudian sintaksis konkret / abstrak dan menghasilkan apa yang ingin Anda hasilkan.
sumber