Mungkin hal utama yang membuangnya adalah yang \s
cocok dengan ruang horizontal dan vertikal. Untuk mencocokkan ruang horizontal saja, gunakan \h
, dan untuk mencocokkan ruang vertikal saja \v
,.
Satu rekomendasi kecil yang saya buat adalah untuk menghindari memasukkan baris baru dalam token. Anda mungkin juga ingin menggunakan operator alternatif %
atau %%
, karena mereka dirancang untuk menangani pekerjaan jenis ini:
grammar Parser {
token TOP {
<headerRow> \n
<valueRow>+ %% \n
}
token headerRow { <.ws>* %% <header> }
token valueRow { <.ws>* %% <value> }
token header { \S+ }
token value { \S+ }
token ws { \h* }
}
Hasil dari Parser.parse($dat)
ini adalah sebagai berikut:
「ID Name Email
1 test test@email.com
321 stan stan@nowhere.net
」
headerRow => 「ID Name Email」
header => 「ID」
header => 「Name」
header => 「Email」
valueRow => 「 1 test test@email.com」
value => 「1」
value => 「test」
value => 「test@email.com」
valueRow => 「 321 stan stan@nowhere.net」
value => 「321」
value => 「stan」
value => 「stan@nowhere.net」
valueRow => 「」
yang menunjukkan kepada kita bahwa tata bahasa telah berhasil mengurai segalanya. Namun, mari kita fokus pada bagian kedua dari pertanyaan Anda, yang Anda inginkan tersedia dalam variabel untuk Anda. Untuk melakukan itu, Anda harus menyediakan kelas tindakan yang sangat sederhana untuk proyek ini. Anda cukup membuat kelas yang metodenya cocok dengan metode tata bahasa Anda (meskipun yang sangat sederhana, seperti value
/ header
yang tidak memerlukan pemrosesan khusus selain pengetatan, dapat diabaikan). Ada beberapa cara yang lebih kreatif / ringkas untuk menangani pemrosesan milik Anda, tetapi saya akan menggunakan pendekatan ilustrasi yang cukup sederhana. Inilah kelas kami:
class ParserActions {
method headerRow ($/) { ... }
method valueRow ($/) { ... }
method TOP ($/) { ... }
}
Setiap metode memiliki tanda tangan ($/)
yang merupakan variabel pencocokan regex. Jadi sekarang, mari kita bertanya informasi apa yang kita inginkan dari setiap token. Di baris tajuk, kami ingin setiap nilai tajuk, berturut-turut. Begitu:
method headerRow ($/) {
my @headers = $<header>.map: *.Str
make @headers;
}
Setiap tanda dengan quantifier di atasnya akan diperlakukan sebagai Positional
, sehingga kami juga bisa mengakses setiap pertandingan sundulan individu dengan $<header>[0]
, $<header>[1]
, dll Tapi mereka adalah pertandingan benda, jadi kami hanya cepat stringify mereka. The make
perintah memungkinkan token lain untuk mengakses data khusus yang kami buat.
Baris nilai kami akan terlihat identik, karena $<value>
token adalah hal yang kami pedulikan.
method valueRow ($/) {
my @values = $<value>.map: *.Str
make @values;
}
Ketika kita sampai pada metode terakhir, kita akan ingin membuat array dengan hash.
method TOP ($/) {
my @entries;
my @headers = $<headerRow>.made;
my @rows = $<valueRow>.map: *.made;
for @rows -> @values {
my %entry = flat @headers Z @values;
@entries.push: %entry;
}
make @entries;
}
Di sini Anda dapat melihat bagaimana kami mengakses hal-hal yang kami proses headerRow()
dan valueRow()
: Anda menggunakan .made
metode ini. Karena ada beberapa valueRows, untuk mendapatkan masing-masing made
nilainya, kita perlu melakukan peta (ini adalah situasi di mana saya cenderung menulis tata bahasa saya hanya <header><data>
di tata bahasa, dan mendefinisikan data sebagai beberapa baris, tetapi ini adalah cukup sederhana itu tidak terlalu buruk).
Sekarang kita memiliki header dan baris dalam dua array, itu hanya masalah membuat mereka menjadi array hash, yang kita lakukan dalam for
loop. The flat @x Z @y
just interolates elemen, dan penugasan hash Melakukan Apa Yang Kami Maksud, tetapi ada cara lain untuk mendapatkan array dalam hash yang Anda inginkan.
Setelah selesai, Anda baru saja make
melakukannya, dan kemudian akan tersedia di made
bagian parse:
say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => test@email.com, ID => 1, Name => test} {Email => stan@nowhere.net, ID => 321, Name => stan} {}]
Cukup umum untuk membungkus ini menjadi suatu metode, seperti
sub parse-tsv($tsv) {
return Parser.parse($tsv, :actions(ParserActions)).made
}
Dengan begitu Anda bisa mengatakannya
my @entries = parse-tsv($dat);
say @entries[0]<Name>; # test
say @entries[1]<Email>; # stan@nowhere.net
Nil
. Sejauh ini umpan baliknya cukup mandul, bukan? Untuk debugging, unduh komaide jika Anda belum melakukannya, dan / atau lihat Bagaimana pelaporan kesalahan dalam tata bahasa ditingkatkan? . Anda punyaNil
karena pola Anda diasumsikan mundur semantik. Lihat jawaban saya tentang itu. Saya sarankan Anda menghindari mundur. Lihat jawaban @ user0721090601 tentang itu. Untuk kepraktisan dan kecepatan, lihat jawaban JJ. Juga, Pengantar jawaban umum untuk "Saya ingin mengurai X dengan Raku. Adakah yang bisa membantu?" .