2011-01-15 9 views
4

Ich habe folgende EingabeMit Parse :: RecDescent

@Book{press, 
    author = "Press, W. and Teutolsky, S. and Vetterling, W. and Flannery B.", 
    title  = "Numerical {R}ecipes in {C}: The {A}rt of {S}cientific {C}omputing", 
    year  = 2007, 
    publisher = "Cambridge University Press" 
} 

und ich habe eine Grammatik für RecDescent Parser-Generator zu schreiben. Daten am Ausgang sollten für die XML-Struktur geändert werden und sollen wie folgt aussehen:

<book> 
    <keyword>press</keyword> 
    <author>Press, W.+Teutolsky, S.+Vetterling, W.+Flannery B.</author> 
    <title>Numerical {R}ecipes in {C}: The {A}rt of {S}cientific {C}omputing</title> 

    <year>2007</year> 
    <publisher>Cambridge University Press</publisher> 
</book> 

Zusätzliche und wiederholten Felder sollten als Fehler gemeldet werden (richtige Nachricht mit Zeilennummer und keine weiteren Analyse). Ich habe versucht, mit etwas wie folgt zu beginnen:

use Parse::RecDescent; 

open(my $in, "<", "parsing.txt") or die "Can't open parsing.txt: $!"; 

my $text; 
while (<$in>) { 
    $text .= $_; 
} 

print $text; 

my $grammar = q { 
    beginning: "\@Book\{" keyword fields "\}"   { print "<book>\n",$item[2],$item[3],"</book>"; } 
    keyword: /[a-zA-Z]+/ ","       { return " <keyword>".$item[1]."</keyword>\n"; } 
    fields: one "," two "," tree "," four    { return $item[1].$item[3].$item[5].$item[7]; } 
    one: "author" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  return " <author>",$item[4],"</author>\n"; } 
    two: "title" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  return " <title>",$item[4],"</title>\n"; } 
    three: "year" "=" /[0-2][0-9][0-9][0-9]/   { return " <year>",$item[3],"</year>\n"; } 
    four: "publisher" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" 
                 { $item[4] =~ s/\sand\s/\+/g; 
                  return " <publisher>",$item[4],"</publisher>\n"; } 
}; 

my $parser = new Parse::RecDescent($grammar) or die ("Bad grammar!"); 
defined $parser->beginning($text) or die ("Bad text!"); 

Aber ich weiß nicht einmal, ob es der richtige Weg ist, es zu tun. Bitte helfen Sie.

Es gibt noch ein kleines Problem. Tags bei der Eingabe sind möglicherweise nicht in dieser bestimmten Reihenfolge, aber jedes Tag kann nur einmal vorkommen. Muss ich für alle Permutationen von (Autor, Titel, Jahr, Verlag) Unterregeln schreiben? Weil ich kam mit:

fields: field "," field "," field "," field 
field: one | two | three | four 

aber es ist offensichtlich nicht verhindern, Tags zu wiederholen.

+2

Sieht aus wie Sie zu einem guten Start sind. Welches Problem hast du? – cam

+1

Es gibt eine Grenze dafür, wie viel Arbeit Sie von Ihrer Grammatik erwarten sollten. Versuche nicht, die Nichtwiederholung in deiner Grammatik zu erzwingen. das ist etwas, mit dem Sie umgehen können, sobald Sie es in eine geeignete Datenstruktur geparst haben. Anstatt also direkt von BibTeX zu XML zu wechseln, analysieren Sie eine Zwischenstruktur, führen Berechnungen für die Struktur durch und geben sie anschließend in XML aus. –

Antwort

9

Zuerst haben Sie einen Tippfehler: tree anstelle von three.

lief ich Ihr Programm aber hinzugefügt, um die Zeilen:

use strict; 
use warnings; # you should always have strict and warnings on 
$::RD_HINT = 1; # Parse::RecDescent hints 
$::RD_TRACE = 1; # Parse::RecDescent trace 

und bekam diese Debug-Ausgabe:

1|beginning |>>Matched terminal<< (return value: | 
    |   |[@Book{])        | 
1|beginning |          |"press,\n author = "Press, 
    |   |          |W. and Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
1|beginning |Trying subrule: [keyword]    | 
2| keyword |Trying rule: [keyword]    | 
2| keyword |Trying production: [/[a-zA-Z]+/ ','] | 
2| keyword |Trying terminal: [/[a-zA-Z]+/]  | 
2| keyword |>>Matched terminal<< (return value: | 
    |   |[press])        | 
2| keyword |          |",\n author = "Press, W. and 
    |   |          |Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
2| keyword |Trying terminal: [',']    | 
2| keyword |>>Matched terminal<< (return value: | 
    |   |[,])         | 
2| keyword |          |"\n author = "Press, W. and 
    |   |          |Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
2| keyword |Trying action       | 
1|beginning |>>Matched subrule: [keyword]<< (return| 
    |   |value: [ <keyword>press</keyword> ]| 
1|beginning |          |"press,\n author = "Press, 
    |   |          |W. and Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
1|beginning |Trying subrule: [fields]    | 
2| fields |Trying rule: [fields]     | 
2| fields |Trying production: [one ',' two ',' | 
    |   |three ',' four]      | 
2| fields |Trying subrule: [one]     | 
3| one |Trying rule: [one]     | 
3| one |Trying production: ['author' '=' '\"' | 
    |   |/[a-zA-Z\s\.\,{}\:]+/ '\"']   | 
3| one |Trying terminal: ['author']   | 
3| one |<<Didn't match terminal>>    | 
3| one |<<Didn't match rule>>     | 
2| fields |<<Didn't match subrule: [one]>>  | 
2| fields |<<Didn't match rule>>     | 
1|beginning |<<Didn't match subrule: [fields]>> | 
1|beginning |<<Didn't match rule>>     | 
Bad text! at parser.pl line 32, <$in> line 6. 

Dies zeigt, dass es one bei Subrule stecken wird immer, und dass press, wird immer wieder gestellt auf den Eingabestrom. Dies liegt daran, dass Sie return anstelle von $return = als Parse :: RecDescent-Handbuch says you should verwenden.

Darüber hinaus können Sie nach der Zuweisung an die $return Variable nicht mehr eine Liste zurückgeben und müssen die Zeichenfolgen manuell verketten.

Hier ist das Endergebnis:

use strict; 
use warnings; 
use Parse::RecDescent; 

open(my $in, "<", "parsing.txt") or die "Can't open parsing.txt: $!"; 

my $text; 
while (<$in>) { 
    $text .= $_; 
} 

print $text; 

my $grammar = q { 
    beginning: "\@Book\{" keyword fields /\s*\}\s*/   { print "<book>\n",$item[2],$item[3],"</book>"; } 
    keyword: /[a-zA-Z]+/ ","       { $return = " <keyword>$item[1]</keyword>\n"; } 
    fields: one /,\s*/ two /,\s*/ three /,\s*/ four    { $return = $item[1].$item[3].$item[5].$item[7]; } 
    one: "author" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  $return = " <author>$item[4]</author>\n"; } 
    two: "title" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  $return = " <title>$item[4]</title>\n"; } 
    three: "year" "=" /[0-2][0-9][0-9][0-9]/   { $return = " <year>$item[3]</year>\n"; } 
    four: "publisher" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" 
                 { $item[4] =~ s/\sand\s/\+/g; 
                  $return = " <publisher>$item[4]</publisher>\n"; } 
}; 

my $parser = new Parse::RecDescent($grammar) or die ("Bad grammar!"); 
defined $parser->beginning($text) or die ("Bad text!"); 
+0

Das '$ return =' anstelle von 'return' hat sehr geholfen. – marooou