gpt4 book ai didi

csv - 如何定义 Raku 语法来解析 TSV 文本?

转载 作者:行者123 更新时间:2023-12-04 11:17:27 25 4
gpt4 key购买 nike

我有一些 TSV 数据

ID     Name    Email
1 test test@email.com
321 stan stan@nowhere.net

我想将其解析为哈希列表
@entities[0]<Name> eq "test";
@entities[1]<Email> eq "stan@nowhere.net";

我在使用换行元字符从值行分隔标题行时遇到问题。我的语法定义:
use v6;

grammar Parser {
token TOP { <headerRow><valueRow>+ }
token headerRow { [\s*<header>]+\n }
token header { \S+ }
token valueRow { [\s*<value>]+\n? }
token value { \S+ }
}

my $dat = q:to/EOF/;
ID Name Email
1 test test@email.com
321 stan stan@nowhere.net
EOF
say Parser.parse($dat);

但这又回来了 Nil .我想我误解了 raku 中关于正则表达式的一些基本知识。

最佳答案

可能主要是因为 \s匹配水平和垂直空间。要仅匹配水平空间,请使用 \h , 并仅匹配垂直空间,\v .

我提出的一个小建议是避免在 token 中包含换行符。您可能还想使用交替运算符 %%% ,因为它们是为处理此类工作而设计的:

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* }
}
Parser.parse($dat)的结果原因如下:
「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 => 「」

这向我们表明语法已成功解析所有内容。但是,让我们关注问题的第二部分,即您希望它在变量中可用。为此,您需要提供一个对于该项目来说非常简单的操作类。您只需创建一个其方法与您的语法方法匹配的类(尽管非常简单的类,例如 value/ header 除了字符串化之外不需要特殊处理,可以忽略)。有一些更有创意/紧凑的方法来处理你的处理,但我会用一种相当基本的方法来说明。这是我们的类(class):
class ParserActions {
method headerRow ($/) { ... }
method valueRow ($/) { ... }
method TOP ($/) { ... }
}

每个方法都有签名 ($/)这是正则表达式匹配变量。所以现在,让我们问问我们想要从每个 token 中获得什么信息。在标题行中,我们希望每个标题值都排成一行。所以:
  method headerRow ($/) { 
my @headers = $<header>.map: *.Str
make @headers;
}

任何带有量词的标记都将被视为 Positional ,因此我们还可以使用 $<header>[0] 访问每个单独的 header 匹配项, $<header>[1] ,等等。但那些是匹配对象,所以我们只是快速地将它们字符串化。 make命令允许其他 token 访问我们创建的这个特殊数据。

我们的值行看起来是一样的,因为 $<value> token 是我们关心的。
  method valueRow ($/) { 
my @values = $<value>.map: *.Str
make @values;
}

当我们使用最后一个方法时,我们将要创建带有哈希值的数组。
  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;
}

在这里您可以看到我们如何访问我们在 headerRow() 中处理的内容。和 valueRow() :您使用 .made方法。因为有多个valueRows,要得到它们的每一个 made值,我们需要做一个映射(在这种情况下,我倾向于编写我的语法以在语法中简单地包含 <header><data>,并将数据定义为多行,但这很简单,还不错)。

现在我们有两个数组中的标题和行,只需将它们设为散列数组即可,我们在 for 中执行此操作。环形。 flat @x Z @y只是插入元素,散列分配就是我们的意思,但还有其他方法可以让数组以您想要的散列形式存在。

完成后,您只需 make它,然后它将在 made 中可用解析:
say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => test@email.com, ID => 1, Name => test} {Email => stan@nowhere.net, ID => 321, Name => stan} {}]

将这些包装成一个方法是很常见的,比如
sub parse-tsv($tsv) {
return Parser.parse($tsv, :actions(ParserActions)).made
}

这样你就可以说
my @entries = parse-tsv($dat);
say @entries[0]<Name>; # test
say @entries[1]<Email>; # stan@nowhere.net

关于csv - 如何定义 Raku 语法来解析 TSV 文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60510667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com