hak0983 has asked for the wisdom of the Perl Monks concerning the following question:

Hiya, I am trying to allow any amount of characters to go on multiple lines of a text area whilst using Parse::Recdescent, kind of pattern matching, but am having trouble. It only allows one character per line. How can i overcome this? The problem is the "text: /(.\s)*/" bit. Here is what i have. Cheers

my $mw3= $mw->Button(-text=>"Check brackets", -command => sub{ my $grammar = q { startrule: open text close open: "<" text: /(.\s)*/ close: ">" }; my $parser = Parse::RecDescent->new($grammar); print defined($parser->startrule($mw2->get ("1.0", "500.0"))) ? "NO ERROR\n" : "ERROR"; })->pack(-side=>'left');

janitored by ybiC: Balanced <code> tags around snippet

Replies are listed 'Best First'.
Re: ParseRecdescent and pattern matching problem
by japhy (Canon) on Mar 27, 2005 at 17:41 UTC
    Your regex, /(.\s)*/ is silly. It says "match a non-newline character and then a space, zero or more times". Perhaps you meant /(.*\n)*/, which means "match zero or more non-newline characters and then a newline, zero or more times". But that's not right for you. What you really want is to match as many non-> characters as possible. I'd suggest /[^>]*/.
    _____________________________________________________
    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: ParseRecdescent and pattern matching problem
by tlm (Prior) on Mar 27, 2005 at 17:04 UTC

    My guess is that you have a precedence error in your print statement. Add some parens:

    print(defined($parser->startrule($mw2->get ("1.0", "500.0"))) ? "NO ERROR\n" : "ERROR");

    Correction: no precedence error in the original.

    Although, even if that fixes one problem, it may not be the end of your woes.

    You may find the posts in this recent meditation enlightening.

    And above all else, read the posting FAQ before you send in your next post.

    the lowliest monk

Re: ParseRecdescent and pattern matching problem
by hak0983 (Novice) on Mar 27, 2005 at 19:13 UTC
    I gave your suggestions a try, however, i still cant parse text in my text area, what i need is in between the < and >, any amount of text and on different lines to be able to be typed in. I have given \w\s\d* a try, and this allows me to do this, but doesnt permit chars like !, ", > etc. Any ideas please.
      Which suggestion did you try? The last one?  /[^>]*/

      What sort of text are you expecting to deal with? What are some positive and negative examples? Japhy's suggestion probably isn't exactly what you want either, but what you really want is not clear.

      To help clarify the discussion, here's a complete, runnable script that allows anything to be typed into the Text widget, and then reports parser results whenever the "Check brackets" button is clicked.

      #!/usr/bin/perl use strict; use Tk; use Parse::RecDescent; my $mw = new MainWindow; my $mw2 = $mw->Text()->pack(); my $mw3 = $mw->Button(-text=>"Check brackets", -command => [ \&parser, $mw2 ] )->pack(); MainLoop; sub parser { my $txt = shift; my $grammar = q { startrule: open text close { print "\n$item[2] " } open: "<" text: /([^>]*)/ close: ">" }; my $parser = Parse::RecDescent->new($grammar); if ( defined( $parser->startrule( $txt->get( "1.0", "end" )))) { print "NO ERROR\n"; } else { print "TEXT COULD NOT BE PARSED\n"; } }
      When I run that and type anything that begins with "<" and contains a ">" anywhere afterwards, I get "NO ERROR" along with the portion of the string that matched the "text" part of the rule. So each of the following examples, if entered at the beginning of the Text widget, had "NO ERROR":
      <tag> # example 1 <> # example 2 <<<<<> # example 3 <!@#$%^&*(){}[] |`~'"> # example 4 <outer <nested tag> tag> extra text. # example 5
      All it would take to make any of those test strings return a parse error would be: (1) have anything other than "<" as the first non-whitespace character, or (2) remove every ">".

      Maybe when you see what gets matched by "text" in your rule, you'll decide that this isn't really the sort of grammar you want, and you should study the RecDescent man page a little more to figure out the appropriate design for the rules that will match only the strings you really want.

      (updated to clarify some of the explanation, and corrected the conditions that lead to a parser error)

      One more update: since your callback (and my version of it) is currently written to create a new "parser" object every time it's called, maybe what you want (just for doing development, at least) is another text widget where you can paste in and edit the grammar that you pass to Parse::RecDescent. In that case, be sure to check the return value from Parse::RecDescent->new, so you'll know when your editing yields an unusable grammar.