如何使用 Grammar 分割一個(gè)有規(guī)律的文本文件? 首先這個(gè)文本有規(guī)律, 但是卻是多行的。
我想將這樣的文檔分為獨(dú)立的. 比如下面這個(gè)例子, 我想將他們分成3個(gè)獨(dú)立的文本, 每個(gè)文本包含: [時(shí)間] Title 以及下面的 content lines. 實(shí)際的文件會(huì)有上千個(gè), 最終輸出的文本的名字是按照括號(hào)里面的時(shí)間來(lái)。
sample.txt
[28/04/2015 12:32] Title1
content line 1
content line 2
content line 3
content line 4
content line 5
balabala
balabala
[28/04/2015 12:16] Title2
content line 6
balabala
content line 7
[27/04/2015 17:30] ?Title3
content line 8
content line 9
content line 10
下面是解析:
#use Grammar::Tracer;
#use Grammar::Debugger;
grammar StructedText {
token TOP { ^ <entry>+ $ }
token entry {
<head> \s* # 每一項(xiàng)有一個(gè)標(biāo)題
<line>+ \s* # 每個(gè)標(biāo)題下面有很多行
}
token head { '[' <datetime> ']' \s+ <title> }
token datetime { <filedate> \s+ <filetime> }
token filedate { [\d+]+ % '/' }
token filetime { [\d+]+ % ':' }
token title { \N+ }
token line {
[
<!head> # 前面不是 head 標(biāo)題
. # 點(diǎn)號(hào)匹配換行符
]+
}
}
# Method 'ast' not found for invocant of class 'Str'
# make ~$<filetime>.subst(':', '-', :g).ast;
class StructedText::Actions {
method line($/) { $/.make: ~$/ }
method title($/) { $/.make: ~$/}
method datetime($/) { $/.make: ~$/.subst(rx/<[:/]>/, '-', :g) }
method head($/) { $/.make: ~$<datetime>.ast }
method entry($/) { make $<head>.ast => $<line>?.made; }
method TOP($/) { $/.make: $<entry>?.ast; }
}
my $actions = StructedText::Actions.new;
my $parsed = StructedText.parsefile('sample.txt', :$actions).made;
if $parsed {
for @$parsed -> $e {
say ~$e.key;
}
}
只打印時(shí)間:
28-04-2015 12-32
28-04-2015 12-16
27-04-2015 17-30
下面是完整的分割代碼:
grammar StructedText {
token TOP { ^ <entry>+ $ }
token entry {
<head> \s* # 每一項(xiàng)有一個(gè)標(biāo)題
<line>+ \s* # 每個(gè)標(biāo)題下面有很多行
}
token head { '[' <datetime> ']' \s+ <title> }
token datetime { <filedate> \s+ <filetime> }
token filedate { [\d+]+ % '/' }
token filetime { [\d+]+ % ':' }
token title { \N+ }
token line {
[
<!head> # 前面不是 head 標(biāo)題
. # 點(diǎn)號(hào)匹配換行符
]+
}
}
class StructedText::Actions {
method line ($/) { $/.make: ~$/ }
method filedate($/) { $/.make: ~$/.subst(rx/<[:/]>/, '-', :g) }
method head ($/) { $/.make: ~$/.subst(rx/<[:/]>/, '-', :g) }
method entry ($/) { make $<head>.ast => $<line>?.made; }
method TOP ($/) { $/.make: $<entry>?.ast; }
}
my $actions = StructedText::Actions.new;
my $parsed = StructedText.parsefile('sample.txt', :$actions).made;
if $parsed {
for @$parsed -> $e {
my $filename = ~$e.key.match(/'[' <( <-[\[\]]>+ )> ']'/) ~ ".txt";
my $fh = open $filename, :w;
$fh.say: ~$e.key;
for $e.value -> $v {
$fh.say: $v;
}
$fh.close;
say "生成文件 $filename ";
}
}
<(
和 )>
是只捕獲整個(gè)匹配中的一部分。這里即只捕獲時(shí)間, 不包括 [
和 ]
字符。match
方法返回匹配到的對(duì)象。