如何在Raku的comb函数中使用Grammar中的正则表达式?
问题描述
我想在Raku的comb函数中使用Grammar内定义的正则表达式,而非独立正则表达式。比如在下面解析journalctl日志的代码里,我希望把MAIN子程序中的&h替换成类似&Journalctl::full_log的内容:
role Log { token preamble { ... }; token message { <-preamble>* }; regex full_log { <preamble> <message> }; } grammar Journalctl does Log { token date { \S+\s\d\d\s\d\d\:\d\d\:\d\d}; token hostname { \S* }; token ctl_unit { <-[\[]>+ }; token pid { \d+ }; regex preamble { <date> <.ws> <hostname> <.ws> <ctl_unit> \[ <pid> \]\: }; } sub MAIN( ) { my regex h { h. }; for $*IN.comb(&h) -> $wof { # FIXME say $wof; } }
参考的journalctl日志示例:
Jun 25 14:45:54 cpu-hostname systemd-timesyncd[725]: Initial synchronization to time server 185.125.190.56:123 (ntp.ubuntu.com). Jun 25 14:45:54 cpu-hostname systemd-resolved[722]: Clock change detected. Flushing caches.
解决方案
Grammar中定义的正则是类方法,无法直接通过&符号传递给comb(comb需要能直接匹配字符串的Callable),可以通过以下两种方式实现需求:
方法一:用闭包包装Grammar正则调用
将Grammar的正则调用封装成闭包,传递给comb:
sub MAIN( ) { for $*IN.comb(-> $str { so $str ~~ Journalctl::full_log }) -> $entry { say $entry; } }
方法二:直接提取Grammar正则作为Callable
可以直接获取Grammar中定义的正则规则,作为Callable传入comb,同时修正原代码中message token的错误定义:
role Log { token preamble { ... }; # 修正message定义:<-preamble>*是错误写法,改为匹配行内所有字符 token message { \N* }; regex full_log { <preamble> <message> }; } grammar Journalctl does Log { token date { \S+\s\d\d\s\d\d\:\d\d\:\d\d}; token hostname { \S* }; token ctl_unit { <-[\[]>+ }; token pid { \d+ }; regex preamble { <date> <.ws> <hostname> <.ws> <ctl_unit> \[ <pid> \]\: }; } sub MAIN( ) { my $full-log-rule = Journalctl.full_log; for $*IN.comb($full-log-rule) -> $entry { say $entry; } }
额外说明
- 原代码中
Log角色的messagetoken使用<-preamble>*是错误的,<-[...]>仅用于字符类否定,无法排除一个token,改用\N*可以匹配行内所有非换行字符,符合日志内容的格式。 comb会自动提取所有匹配正则的片段,结合修正后的full_log规则,可以正确拆分每条journalctl日志条目。
内容的提问来源于stack exchange,提问作者mikeLundquist
相关产品推荐
相关产品推荐

