Tuesday 25 December 2007

Pattern, Matcher in Java



お留守番中なんだが、また、Java をいじってます。

Parser を書くのに、うっかりScannerを使ってしまって、こいつが... delemiter に "\s*" を使うと、「一文字ずつしかマッチしない」という技を出す。まぁ、そうねぇ。そういう仕様もありと言えばありだよな。不便だけど。\b とかは使えないらしいです。hasNext() がmaximum match してくれれば良いんだが... たぶん、まず、delemiter で分解してからscan しているんだろうなぁ。

で、どうしようもなくて、

 while(scanner.hasNext(namePat1)) {
  s += scanner.next(namePat1);
 }

とかやってました。これって、o(n^2) じゃん。学生にやるなって言っていることだよ。まぁ、富豪的視点からは放っておいてもいいんだが...

なので、PatternとMatcher を見直して書き直し。

 if (matcher.usePattern(tokenPat).find(position)) {

とかやれば良いのかと思ったんだが、
 tokenPat = Pattern.compile("^[(){},;~]");
では、position が >0 だと、必ず fail するらしい。^ を取ると、パターンが出て来るまで skip されてしまう。どうすりゃ良いんだよ。

The lookingAt method attempts to match the input sequence, starting at the beginning, against the pattern.

The find method scans the input sequence looking for the next subsequence that matches the pattern.

ということらしいんですけどね。良く見てみると lookingAt にはregionってのがあるのを発見!

結局、^ は取り除いて、
  matcher.region(position, end);
  if (matcher.usePattern(tokenPat).lookingAt()) {
   position = matcher.end();
という風に書けば良いみたいです。lookingAt()に position を書けないのは不便。Matcher が next() を持っていればParserに便利なんだが...

Pattern は、Perl のRegexを参考に作ったみたいだが... Perl のように「こう動いて欲しいと思うように大体作られている」というわけではないらしい。Perl だったら、

 if (s/^[(){},;~]//) { ...

と書くでしょう。

No comments: