Rust 太难了, 哭了。有一块儿爬六峰山的吗?拍照留恋。

山下

img

Learning Rust

img

Rust 生命周期

生命周期太难了, 哭了。

Zz

img

照片

img

网易云音乐歌单

看剧不如听歌。

语法

Rust 语法太难记了, 反直觉。又哭了。

关于

Perl 6 is died, Long live Raku.

学习正则表达式

regexes in raku is awesome!

学习 Grammar

Grammar in raku is awesome!

学习 Action

Action in raku is awesome!

Web Site

Rust 太难了。 Rust 怎么这么难啊! 真的太难了。 磕学家才学得会。
Rust 太难了, 哭了。
2020年夏天, 天气晴, 大兴区。

天池

img

曙暮光条

img

做饭

img

提取 ipconfig 命令的部分输出

数据样例

下面这段文本是 IPCONFIG /ALL 命令的输出结果:

Windows IP 配置

   主机名  . . . . . . . . . . . . . : Win10-2020QJFDK
   主 DNS 后缀 . . . . . . . . . . . : 
   节点类型  . . . . . . . . . . . . : 混合
   IP 路由已启用 . . . . . . . . . . : 否
   WINS 代理已启用 . . . . . . . . . : 否

以太网适配器 本地连接* 9:

   媒体状态  . . . . . . . . . . . . : 媒体已断开连接
   连接特定的 DNS 后缀 . . . . . . . : 
   描述. . . . . . . . . . . . . . . : Sangfor SSL VPN CS Support System VNIC
   物理地址. . . . . . . . . . . . . : 00-FF-05-0D-13-A2
   DHCP 已启用 . . . . . . . . . . . : 否
   自动配置已启用. . . . . . . . . . : 是

无线局域网适配器 WLAN:

   媒体状态  . . . . . . . . . . . . : 媒体已断开连接
   连接特定的 DNS 后缀 . . . . . . . : 
   描述. . . . . . . . . . . . . . . : Realtek RTL8192EU Wireless LAN 802.11n USB 2.0 Network Adapter
   物理地址. . . . . . . . . . . . . : 30-B4-9E-40-FF-0C
   DHCP 已启用 . . . . . . . . . . . : 是
   自动配置已启用. . . . . . . . . . : 是

无线局域网适配器 本地连接* 10:

   媒体状态  . . . . . . . . . . . . : 媒体已断开连接
   连接特定的 DNS 后缀 . . . . . . . : 
   描述. . . . . . . . . . . . . . . : Microsoft Wi-Fi Direct Virtual Adapter
   物理地址. . . . . . . . . . . . . : 32-B4-9E-40-FF-0C
   DHCP 已启用 . . . . . . . . . . . : 是
   自动配置已启用. . . . . . . . . . : 是

以太网适配器 以太网:

   连接特定的 DNS 后缀 . . . . . . . : 
   描述. . . . . . . . . . . . . . . : Realtek PCIe GBE Family Controller
   物理地址. . . . . . . . . . . . . : 54-E1-AD-48-66-22
   DHCP 已启用 . . . . . . . . . . . : 否
   自动配置已启用. . . . . . . . . . : 是
   本地链接 IPv6 地址. . . . . . . . : fe80::4195:49da:a7ec:9e68%6(首选) 
   IPv4 地址 . . . . . . . . . . . . : 192.168.0.68(首选) 
   子网掩码  . . . . . . . . . . . . : 255.255.255.0
   默认网关. . . . . . . . . . . . . : 192.168.0.1
   DHCPv6 IAID . . . . . . . . . . . : 324329901
   DHCPv6 客户端 DUID  . . . . . . . : 00-01-00-01-26-4E-B2-11-54-E1-AD-48-66-22
   DNS 服务器  . . . . . . . . . . . : 61.128.128.68
   TCPIP 上的 NetBIOS  . . . . . . . : 已启用

分别提取含有"适配器"文字下面的「描述」、「物理地址」、「IP地址」、「子网掩码」、「默认网关」、「DNS 服务器」等信息。某些适配器下面可能实际没有「IP地址」、「子网掩码」、「默认网关」、「DNS 服务器」等,有就提取,没有就略过。

Grammar

unit grammar IPConfig::Grammar;

token TOP { <section>+ %% \n* }
token section {
    <header>
    \n
    <config>+
}

token header { ^^ \N+  \n         }
token config { ^^ \s+ \N+ $$ \n*  }

Action

unit class IPConfig::Action;

method TOP($/) {
    make $/<section>».made;
}

method section($/) {
    my $configs = $/<config>».made;
    if $configs.elems > 0 {
        make ~$/<header>  ~ $configs.join('');
    } else {
        make Empty;
    }
}

method header($/) {
    make ~$/;
}

method config($/ is copy) {
    my $text = ~$/;
    if $text.contains(/'描述' | '物理地址' | IPv[4|6] ' ' 地址 | '子网掩码' | DNS ' ' 服务器/) {
         $/.make(~$/);
    } else {
        make Empty;
    }
}

提取脚本

use lib '.';
use IPConfig::Grammar;
use IPConfig::Action;

my $ipconfig = IPConfig::Grammar.parsefile(
    "data/ifconfig.txt",
    :actions(IPConfig::Action)
).made;

.Str.say for @$ipconfig;

输出

以太网适配器 本地连接* 9:
   描述. . . . . . . . . . . . . . . : Sangfor SSL VPN CS Support System VNIC
   物理地址. . . . . . . . . . . . . : 00-FF-05-0D-13-A2

无线局域网适配器 WLAN:
   描述. . . . . . . . . . . . . . . : Realtek RTL8192EU Wireless LAN 802.11n USB 2.0 Network Adapter
   物理地址. . . . . . . . . . . . . : 30-B4-9E-40-FF-0C

无线局域网适配器 本地连接* 10:
   描述. . . . . . . . . . . . . . . : Microsoft Wi-Fi Direct Virtual Adapter
   物理地址. . . . . . . . . . . . . : 32-B4-9E-40-FF-0C

以太网适配器 以太网:
   描述. . . . . . . . . . . . . . . : Realtek PCIe GBE Family Controller
   物理地址. . . . . . . . . . . . . : 54-E1-AD-48-66-22
   本地链接 IPv6 地址. . . . . . . . : fe80::4195:49da:a7ec:9e68%6(首选) 
   IPv4 地址 . . . . . . . . . . . . : 192.168.0.68(首选) 
   子网掩码  . . . . . . . . . . . . : 255.255.255.0
   默认网关. . . . . . . . . . . . . : 192.168.0.1
   DNS 服务器  . . . . . . . . . . . : 61.128.128.68
Less Than Awesome.

使用 %% 提取文本块儿

数据样例

section.txt 中的本文为样例数据:

123,456,789
=begin code
999,333,666
145,123,120
=end code
10,20,30
10,10,10
=begin code
567,555,578
678,679,665
710,720,715
=end code
321,654,987
=begin code
312,555
=end code

要求把 =begin code=end code 之间的所有数字分别提取出来。

Grammar

Grammar 的结构如下, 其中 Section 目录下分别是 Grammar 和 Action 模块, data 目录下是样例数据 section.txt:

├── Section
│   ├── Actions.pm6
│   └── Grammar.pm6
├── data
│   ├── section.txt
├── extract-section.p6
use Grammar::Debugger;
use Grammar::Tracer;

unit grammar Section::Grammar;

token TOP {
   ^  <section>+ %% <separator> $
}

token section {
    <line>+
}

token line {
   ^^ [\d+]+ %% ',' $$ \n
}

token separator {
    |  ^^ '=begin code' $$ \n
    |  ^^ '=end code' $$ \n*
}

其中 Grammar::DebuggerGrammar::Tracer 模块用于调试 grammar, 需要放在 grammar 模块的行首:

use Grammar::Debugger;
use Grammar::Tracer;

Action

unit class Section::Actions;

method TOP($/) {
     make $/.values».made;
}

method section($/) {
    make ~$/.trim;
}

method line($/) {
    make ~$/.trim;
}

method separator($/) {
    make Empty;
}

解析

不使用 Action

use lib '.';
use Section::Grammar;

my $parsed = Section::Grammar.parsefile(@*ARGS[0] // 'data/section.txt');
.Str.say for $parsed<section>;

输出

123,456,789

999,333,666
145,123,120

10,20,30
10,10,10

567,555,578
678,679,665
710,720,715

321,654,987

312,555

使用 Action

use lib '.';
use Section::Grammar;
use Section::Actions;

my $parsed = Section::Grammar.parsefile(
    @*ARGS[0] // 'data/section.txt',
    :actions(Section::Actions)
).made;

.Str.say for @$parsed;

输出

123,456,789
999,333,666
145,123,120
10,20,30
10,10,10
567,555,578
678,679,665
710,720,715
321,654,987
312,555

再用 %% 提取文本块儿

数据样例

Here's some unimportant text.
=begin code
This code block is what we're after.
We'll use 'ff' to get it.
=end code
More unimportant text.
=begin code
I want this line.
and this line as well.
HaHa.
=end code
More unimport text.
=begin code
Let's to go home.
=end code

Grammar

use Grammar::Debugger;
use Grammar::Tracer;

unit grammar Range::Grammar;

token TOP {
   ^  <un-important-line>+ %% <section> $
}

token section {
   <begin> ~ <end> <line>+?
}

token un-important-line {
    ^^ \N+ )> \n*
}

token line {
    ^^ \N+ )> \n*
}

token begin {
    ^^ '=begin code' $$ \n*
}

token end {
    ^^ '=end code' $$ \n*
}

Action

unit class Range::Actions;

method TOP($/) {
     make $/.values».made;
}

method section($/) {
    make $/<line>».made;
}

method line($/) {
    make ~$/.trim;
}

method un-important-line($/) {
    make Empty;
}

method begin($/) {
    make Empty;
}

method end($/) {
    make Empty;
}

提取

#!/usr/bin/env perl6

use lib '.';
use Range::Grammar;
use Range::Actions;

my $parsed = Range::Grammar.parsefile(
        @*ARGS[0] // 'data/flip-flop.txt',
        :actions(Range::Actions)
        ).made;

for @$parsed -> $line {
    say $line.raku;
    say '-' x 35;
}

输出

$["This code block is what we're after.", "We'll use 'ff' to get it."]
-----------------------------------
$["I want this line.", "and this line as well.", "HaHa."]
-----------------------------------
$["Let's to go home."]
-----------------------------------

提取文本块儿

数据样例

Here's some unimportant text.
=begin code
This code block is what we're after.
We'll use 'ff' to get it.
=end code
More unimportant text.
=begin code
I want this line.
and this line as well.
HaHa
=end code
More unimport text.
=begin code
Let's to go home.
=end code

要求提取 =begin code=end code 之间的文本块儿。

Grammar

grammar ExtractSection {
  token start   { ^^ '=begin code' \n          }
  token finish  { ^^ '=end code' \n            }
  token line    { ^^ \N+)> \n                  }
  token section { <start> ~ <finish> <line>+?  }
  token comment { ^^\N+ \n                     }
  token TOP     { [<section> || <comment>]+    } 
}

Action

class ExtractSectionAction {
    method TOP($/)     { make @<section>».ast.List }
    method section($/) { make ~«@<line>.List       }
    method line($/)    { make ~$/.trim             }
    method comment($/) { make Empty                }
}

提取

my $em = ExtractSection.parse(
    $excerpt, 
    :actions(ExtractSectionAction)
).ast;

for @$em -> $line {
    say $line.perl;
    say '-' x 35;
}

输出

$("This code block is what we're after.", "We'll use 'ff' to get it.")
-----------------------------------
$("I want this line.", "and this line as well.", "HaHa")
-----------------------------------
$("Let's to go home.",)
-----------------------------------