views:

499

answers:

2

Assume we want to validate user input, while user is typing in a JTextField. For validating the user input, I wonder if I could use Ragel.

Assume the input should follow this example regex:

[a-z]{2,5}ABC[0-9]+

How can I do this with ragel? Can anybody give a short example how to validate user input "on the fly" (while inputing) with ragel?

The Ragel documentations misses some good examples for a Quick Start, so I ask here.

A: 

I don't know Ragel but to verify a JTextField you'd want to register either a KeyListener or a FocusListener. A KeyListener will let you verify the characters as you type (which sounds like what you want), a FocusListener will do the verification once the user has finished typing and clicked out of the box. IMO the latter is preferrable in most cases, because it's rare that partial input is really what you want to validate.

UPDATE: Actually, Sun have quite an interesting page that offers some other solutions. Changing the underlying Document type of the JTextField seems like quite a neat solution.

GaryF
http://stackoverflow.com/questions/363784/setting-the-tab-policy-in-swings-jtextpane#363967As you see, I know documents ;) But I need a state machine to verify the user input. With a document, I need many regular expressions, depending of how many characters the user already typed (cursor position)
Kai
A: 

You can use EOF actions (section 3.2.2 EOF Actions in the Ragel documentation) for checking of the expressions on the fly with Ragel. They are triggered when end of input buffer is detected in a valid state (including non-final).

Simple example:

  main := ([a-z]{2,5}'ABC'[0-9]+) @/{correct = 1;} %{correct = 1;};

Action "@/" is for all non-final states. It includes starting state so empty string is correct for this case. Action "%" is for final state when entire input buffer matches the pattern. In the example above code for both actions are the same, but final state is often to be processed separately in practice. If it is not needed then the sample above can be simplified:

  main := ([a-z]{2,5}'ABC'[0-9]+) $/{correct = 1;};

The complete Ragel sample with C output for checking the provided pattern is below. I hope that it is not a problem to convert it to Java.

  #include <stdio.h>

  %%{
   machine checker;
   write data;
  }%%

  unsigned char checker( const char *str )
  {
   /* standart Ragel variables */
   const char *p = str, *pe = str + strlen( str ) - 1; //-1 to strip "\n"
   const char *eof = pe;
   int cs;

   unsigned char correct = 0;

   %%{
    action final { printf("entire match"); correct = 1; }
    action partial { printf("partial match"); correct = 1; }

    main := ([a-z]{2,5}'ABC'[0-9]+) @/partial %final;

    write init;
    write exec;
   }%%

   return correct;
  };


  #define BUFSIZE 1024
  int main()
  {
   char buf[BUFSIZE];
   while ( fgets( buf, sizeof(buf), stdin ) != 0 ) {
    printf( "%d\n", checker( buf ));
   }
   return 0;
  }
Artem Zankovich