Có lẽ điều chính khiến nó bị loại bỏ là \s
phù hợp với không gian ngang và dọc. Để phù hợp với không gian ngang, sử dụng\h
và để khớp với không gian dọc , \v
.
Một khuyến nghị nhỏ mà tôi đưa ra là tránh đưa các dòng mới vào mã thông báo. Bạn cũng có thể muốn sử dụng các toán tử thay thế %
hoặc %%
, vì chúng được thiết kế để xử lý loại công việc này:
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* }
}
Kết quả của Parser.parse($dat)
việc này là như sau:
「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 => 「」
trong đó cho chúng ta thấy rằng ngữ pháp đã phân tích thành công mọi thứ. Tuy nhiên, hãy tập trung vào phần thứ hai của câu hỏi của bạn, rằng bạn muốn nó có sẵn trong một biến cho bạn. Để làm điều đó, bạn sẽ cần cung cấp một lớp hành động rất đơn giản cho dự án này. Bạn chỉ cần tạo một lớp có các phương thức khớp với các phương thức ngữ pháp của bạn (mặc dù các phương thức rất đơn giản, như value
/ header
không yêu cầu xử lý đặc biệt bên cạnh chuỗi, có thể bị bỏ qua). Có một số cách sáng tạo / nhỏ gọn hơn để xử lý việc xử lý của bạn, nhưng tôi sẽ đi theo một cách tiếp cận khá thô sơ để minh họa. Đây là lớp học của chúng tôi:
class ParserActions {
method headerRow ($/) { ... }
method valueRow ($/) { ... }
method TOP ($/) { ... }
}
Mỗi phương thức có chữ ký ($/)
là biến khớp regex. Vì vậy, bây giờ, hãy hỏi những thông tin chúng tôi muốn từ mỗi mã thông báo. Trong hàng tiêu đề, chúng tôi muốn mỗi giá trị tiêu đề, trong một hàng. Vì thế:
method headerRow ($/) {
my @headers = $<header>.map: *.Str
make @headers;
}
Bất kỳ mã thông báo nào có bộ định lượng trên đó sẽ được coi là một Positional
, vì vậy chúng tôi cũng có thể truy cập từng đối tượng tiêu đề riêng lẻ với $<header>[0]
,$<header>[1]
, vv Tuy nhiên, đó là những đối tượng phù hợp, vì vậy chúng tôi chỉ nhanh chóng stringify họ. Các make
lệnh cho phép thẻ khác để truy cập dữ liệu đặc biệt này mà chúng tôi đã tạo ra.
Hàng giá trị của chúng tôi sẽ trông giống hệt nhau, bởi vì các $<value>
mã thông báo là thứ chúng tôi quan tâm.
method valueRow ($/) {
my @values = $<value>.map: *.Str
make @values;
}
Khi chúng ta đến phương thức cuối cùng, chúng ta sẽ muốn tạo mảng bằng băm.
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;
}
Tại đây bạn có thể thấy cách chúng tôi truy cập vào nội dung chúng tôi đã xử lý headerRow()
và valueRow()
: Bạn sử dụng .made
phương pháp. Bởi vì có nhiều giá trị, để có được mỗi giá trị của chúngmade
giá trị giá trị chúng, chúng ta cần tạo một bản đồ (đây là tình huống tôi có xu hướng viết ngữ pháp của mình để đơn giản <header><data>
trong ngữ pháp và xác định dữ liệu là nhiều hàng, nhưng đây là đủ đơn giản, nó không quá tệ).
Bây giờ chúng ta có các tiêu đề và hàng trong hai mảng, đơn giản chỉ là biến chúng thành một mảng băm, mà chúng ta thực hiện trong for
vòng lặp. Việc flat @x Z @y
chỉ xen kẽ các phần tử và phép gán băm Does What We We mean, nhưng có nhiều cách khác để có được mảng trong hàm băm bạn muốn.
Khi bạn đã hoàn tất, bạn chỉ cần make
nó, và sau đó nó sẽ có sẵn trong made
phân tích cú pháp:
say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => test@email.com, ID => 1, Name => test} {Email => stan@nowhere.net, ID => 321, Name => stan} {}]
Nó khá phổ biến để bọc chúng thành một phương thức, như
sub parse-tsv($tsv) {
return Parser.parse($tsv, :actions(ParserActions)).made
}
Bằng cách đó bạn chỉ có thể nói
my @entries = parse-tsv($dat);
say @entries[0]<Name>; # test
say @entries[1]<Email>; # stan@nowhere.net
Nil
. Nó khá cằn cỗi theo như phản hồi, phải không? Để gỡ lỗi, hãy tải xuống dấu phẩy nếu bạn chưa có và / hoặc xem Làm thế nào để báo cáo lỗi trong ngữ pháp được cải thiện? . Bạn cóNil
cuz mô hình của bạn giả định ngữ nghĩa quay lui. Xem câu trả lời của tôi về điều đó. Tôi khuyên bạn nên quay lại eschew. Xem câu trả lời của @ user0721090601 về điều đó. Để biết tính thực tế và tốc độ, hãy xem câu trả lời của JJ. Ngoài ra, câu trả lời chung giới thiệu cho "Tôi muốn phân tích X với Raku. Có ai có thể giúp đỡ không?" .