Raku By Example
View me onGitHub
## proto

grammar Perl6VariableNames {

    token variable {
        <sigil> <name>
    }

    #token sigil {
    #    '$' | '@' | '&' | '%' | '::'
    #}

  # 使用 proto
    proto token sigil {*}
    token sigil:sym<$>  { <sym> }
    token sigil:sym<@>  { <sym> }
    token sigil:sym<%>  { <sym> }
    token sigil:sym<&>  { <sym> }
    token sigil:sym<::> { <sym> }

	# [ ... ] are non-capturing groups
	token name {
        <identifier>
        [ '::' <identifier> ] *
    }
	# 标识符以字母开头
    token identifier {
        <alpha> \w+
    }
}

my $match = Perl6VariableNames.parse("@array",:rule('variable'));
say $match;

grammar SigilRichPerl6 is Perl6VariableNames {
    token sigil:sym<ħ> { <sym> } # physicists will love you
}

my $rich = SigilRichPerl6.parse("ħarray",:rule('variable'));
say $rich;

grammar LowBudgetPerl6 is Perl6VariableNames {
    token sigil:sym<$> { '¢' }
}

my $money = LowBudgetPerl6.parse('$array',:rule('variable'));
say $money;

## 解析行程数据

grammar SalesExport::Grammar {
    token TOP { ^ <country>+ $ }
    token country {
        <cname=.name> \n
        <destination>+
    }

    token destination {
        \s+ <dname=.name> \s+ ':' \s+
        <lat=.num> ',' <long=.num> \s+ ':' \s+
        <sales=.integer> \n
    }

    token name    { \w+          }
    token num     { \d+ [\.\d+]? }
    token integer { \d+          }
}

my $string = q:to/THE END/;
Norway
    Oslo : 59.914289,10.738739 : 2
    Bergen : 60.388533,5.331856 : 4
Ukraine
    Kiev : 50.456001,30.50384 : 3
Switzerland
    Wengen : 46.608265,7.922065 : 3
THE END

class SalesExport::Grammar::Actions {
	method destination($/) { make ~$<dname> => $<sales>          }
    method country($/)     { make ~$<cname> => $<destination>    }
    method TOP($/)         { make $<country>>>.made              }
}

my $actions = SalesExport::Grammar::Actions.new;
my $grammar_action = SalesExport::Grammar.parse($string, :actions($actions)).made;

# 获取所有国家的名字
for @$grammar_action -> $p {
    say "$p.key()";
}

say  "-" x 45;
for @$grammar_action -> $p {
    for $p.value() -> $d {
	   for @$d -> $n {
	      say ~$n<dname>;
	   }
	  }
}

say  "-" x 45;

# 计算每个国家卖了多少票
for @$grammar_action -> $c {
    for $c.value() -> $d {
	   my $sales_count=0;
	   for @$d -> $n {
	      $sales_count += ~$n<sales>;
	   }
	   say $sales_count;
	  }
}

## 解析气象数据

grammar StationDataParser {
    token TOP          { ^ <keyval>+ <observations> $             }
    token keyval       { $<key>=[<-[=]>+] '=' \h* $<val>=[\N+] \n }
    token observations { 'Obs:' \h* \n <observation>+             }
    token observation  { $<year>=[\d+] \h* <temp>+ %% [\h*] \n    }
    token temp         { '-'? \d+ \. \d+                          }
}

class StationData {
    has $.name;
    has $.country;
    has @.data;

    submethod BUILD(:%info (:Name($!name), :Country($!country), *%), :@!data) {
    }
}

class StationDataActions {
    method TOP($/) {
        make StationData.new(
            info => $<keyval>.map(*.ast).hash,
            data => $<observations>.ast
        );
    }

    method keyval($/) {
        make ~$<key> => ~$<val>;
    }
    method observations($/) {
        make $<observation>.map(*.ast).grep(*.value.none <= -99);
    }
    method observation($/) {
        make +$<year> => $<temp>.map(*.Num);
    }
}

say StationDataParser.parse( q:to/EOCSV/, :actions(StationDataActions)).ast
Name= Jan Mayen
Country= NORWAY
Lat=   70.9
Long=    8.7
Height= 10
Start year= 1921
End year= 2009
Obs:
1921 -4.4 -7.1 -6.8 -4.3 -0.8  2.2  4.7  5.8  2.7 -2.0 -2.1 -4.0
1922 -0.9 -1.7 -6.2 -3.7 -1.6  2.9  4.8  6.3  2.7 -0.2 -3.8 -2.6
2008 -2.8 -2.7 -4.6 -1.8  1.1  3.3  6.1  6.9  5.8  1.2 -3.5 -0.8
2009 -2.3 -5.3 -3.2 -1.6  2.0  2.9  6.7  7.2  3.8  0.6 -0.3 -1.3
EOCSV

## -------------------------------------------------------------

my $string = "[Wang, Zhiguo; Zhao, Zhiguo] Hangzhou Normal Univ, Ctr Cognit & Brain Disorders, Hangzhou, Zhejiang, Peoples R China; [Wang, Zhiguo; Theeuwes, Jan] Vrije Univ Amsterdam, Dept Cognit Psychol, Amsterdam, Netherlands";

grammar University::Grammar {
    token TOP             { ^ <university> $             }
    token university      { [ <bracket> <info> ]+ % '; ' }
    token bracket         { '[' <studentname>  '] '      }
    token studentname     { <stdname=.info>+ % '; '      }
    token info            { <field>+ % ', '              }
    token field           { <-[,\]\[;\n]>+               }
}

grammar MyUniversity  is University::Grammar {
    token university      { <info>+ % '; ' }
}

my $sr = "Zhejiang Univ, Coll Environm & Resources Sci, Dept Resource Sci, Hangzhou 310029, Peoples R China; La Trobe Univ, Dept Agr Sci, Bundoora, Vic 3083, Australia; Hangzhou Normal Coll, Fac Life Sci, Hangzhou, Peoples R China";

my $parsed = University::Grammar.parse($string);
# my $parsed = MyUniversity.parse($sr);

for @($parsed<university><info>) -> $f {
    say $f<field>[0];
}

## Calc

grammar Calc {
    rule TOP {
        ^ <expression> $
    }
    rule expression {
        | <term>+ %% $<op>=(['+'|'-'])
        | <group>
    }
    rule term {
        <factor>+ %% $<op>=(['*'|'/'])
    }
    rule factor {
        | <value>
        | <group>
    }
    rule group {
        '(' <expression> ')'
    }
    token value {
        | \d+['.' \d+]*
        | '.' \d+
    }
}

say Calc.parse('3*4*5');

## 纸牌游戏

grammar CardGame {

    rule TOP { ^ <deal> $ }

    rule deal {
        <hand>+ % ';'
    }

    rule hand { [ <card> ]**5 }
    token card {<face><suit>}

    proto token suit {*}
    token suit:sym<>  {<sym>}
    token suit:sym<>  {<sym>}
    token suit:sym<>  {<sym>}
    token suit:sym<>  {<sym>}

    token face {:i <[2..9]> | 10 | j | q | k | a }
}

say CardGame.parse("2♥ 5♥ 7♦ 8♣ 9♠");
say CardGame.parse("2♥ a♥ 7♦ 8♣ j♥");

## CarGame with Action

grammar CardGame {

    rule TOP { ^ <deal> $ }

    rule deal {
       :my %*PLAYED = ();
       <hand>+ % ';'
    }

    rule hand { [ <card> ]**5 }
    token card {<face><suit>}

    proto token suit {*}
    token suit:sym<>  {<sym>}
    token suit:sym<>  {<sym>}
    token suit:sym<>  {<sym>}
    token suit:sym<>  {<sym>}

    token face {:i <[2..9]> | 10 | j | q | k | a }
}

class CardGame::Actions {
    method card($/) {
       my $card = $/.lc;
       say "Hey, there's an extra $card"
           if %*PLAYED{$card}++;
   }
}

my $a = CardGame::Actions.new;
say CardGame.parse("a♥ a♥ 7♦ 8♣ j♥", :actions($a));
# "Hey there's an extra a♥"
say CardGame.parse("a♥ 7♥ 7♦ 8♣ j♥; 10♥ j♥ q♥ k♥ a♦",
                   :actions($a));
# "Hey there's an extra j♥"


## 解析逗号分割的字符串

my $string = q:to/THE END/;
Hangzhou Normal Univ, Coll Mat Chem & Chem Engn, Hangzhou 310036, Zhejiang, Peoples R China
Hong Kong Univ, Sci & Technol, Dept Chem, Kowloon, Hong Kong, Peoples R China
Hong Kong Univ, Sci & Technol, Inst Adv Study, Kowloon, Hong Kong, Peoples R China
THE END

grammar CommaSeparated::Grammar {
    token TOP   {^ <line>+ $      }
    token line  { <info> \n       }
    token info  { <field>+ % ', ' }
    token field { <-[,\n]>+       }
}

my $parsed = CommaSeparated::Grammar.parse($string);


# say $parsed<line>[0]<info><field>».Str;

for @($parsed<line>) -> $line {
    # say join ", ", $line<info><field>».Str;
    say  $line<info><field>».Str.[0];
}

## ---------------------------------------------------

## countpairs

grammar WordPairs {
    token TOP { <word-pair>* }
    token word-pair { (\S*) ' ' (\S*) "\n" }
}

class WordPairsActions {
    method word-pair($/) { %dict{$0}.push($1) }
}

my $match = WordPairs.parse("{@*ARGS[0]}".IO.slurp, :actions(WordPairsActions));
say ?$match;

say "The pairs count of the key word \"her\" in wordpairs.txt is {%dict{"her"}.elems}";

## CSV 解析

use CSV::Parser;

my $fh = open "cmgd.csv", :r;
my @lines = "JournalList_cn.txt".IO.lines;
my %iscn;
for @lines[1..*] -> $line {
    my ($iscn, $number) = $line.split(/\s+/);
    %iscn{$iscn} = $number;
}

grammar University::Grammar {
    token TOP             { ^ <university> $             }
    token university      { [ <bracket> <info> ]+ % '; ' }
    token bracket         { '[' <studentname>  '] '      }
    token studentname     { <stdname=.info>+ % '; '      }
    token info            { <field>+ % ', '              }
    token field           { <-[,\]\[;\n]>+               }
}

grammar MyUniversity  is University::Grammar {
    token university      { <info>+ % '; ' }
}

my $parser = CSV::Parser.new(file_handle => $fh,  contains_header_row => False);
my %data;
my $count = 1;
while %data = %($parser.get_line()) {

    my @universitys;
    my @countrires;

    my $parsed;
    if %data{'1'} ~~ /'['/ {
        $parsed = University::Grammar.parse(%data{'1'});
    } else {
        $parsed = MyUniversity.parse(%data{'1'});
    }

    print $count, "\t";
    $count++;

    # 作者数量
    print 1+@$(%data{'0'} ~~ m:g/';'/);
    print "\t";

    # 机构
    for @($parsed<university><info>) -> $f {
        push @universitys, $f<field>[0].Str;
    }

    print join ", ", @universitys.unique;
    print "\t";

    # 国别
    for @($parsed<university><info>) -> $f {
        push @countrires, $f<field>[*-1].Str;
    }

    print join ", ", @countrires.unique;
    print "\t";

    # 学科
    print %iscn{%data{'2'}};
    print "\t";

    # 年份
    say %data{'3'};
}