Personal tools
You are here: Home ブログ 井上 Javaで正規表現
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Recent entries
Apache2.4のリリース予定は来年(2011年)初め(あくまで予定) inoue 2010-12-23
Herokuの発音 inoue 2010-12-20
雑誌記事「ソフトウェア・テストPRESS Vol.9」の原稿公開 inoue 2010-12-18
IPA未踏のニュース inoue 2010-12-15
労基法とチキンゲーム inoue 2010-12-06
フロントエンドエンジニア inoue 2010-12-03
ASCII.technologies誌にMapReduceの記事を書きました inoue 2010-11-25
技術評論社パーフェクトシリーズ絶賛発売中 inoue 2010-11-24
雑誌連載「Emacsのトラノマキ」の原稿(part8)公開 inoue 2010-11-22
RESTの当惑 inoue 2010-11-22
「プログラマのためのUXチートシート」を作りました inoue 2010-11-19
「ビューティフルコード」を読みました inoue 2010-11-16
Categories
カテゴリなし
 
Document Actions

Javaで正規表現

先月末に正規表現の勉強会をしました(http://dev.ariel-networks.com/articles/workshop/regex/)。

良い内容だと思っているのですが、いまいち盛り上がりませんでした。 後日、あるベテランプログラマーに、「Perlなんて言うからダメです。今時の若者はPerlなんて使いません」とたしなめられました。 普段、ぼくはPerlよりsedやawkを使う方が多いのですが、sedやawkでは話が通じないと思い、Perlに日和ったつもりでした。判断が甘かったようです。

今月も続きをやる予定です。 本当はNFAとDFAの話をしたいのですが、また受けが悪そうなので、その辺はさらっと流して、Javaで使う正規表現を全面に押すつもりです。

Java1.4以降、java.util.regexとして標準パッケージで正規表現が使えます。 もうひとつ有名なのはJakartaのregexpです(http://jakarta.apache.org/regexp/index.html)。 その他、利用可能な正規表現の実装は http://regex.info/java.html にまとまっています。

java.util.regexのサンプルコードです。 引数で正規表現のパターンを渡して、標準入力から入力テキストを渡します。

// java5 standard regex test
import java.io.*;
import java.util.*;
import java.util.regex.*;

public class MyRegex {
    public void doit(String pattern) {
        Pattern regex = Pattern.compile(pattern);

        BufferedReader fin = new BufferedReader(new InputStreamReader(System.in));
        try {
            while (true) {
                System.out.println("input any text");
                String s = fin.readLine();

                Matcher m = regex.matcher(s);
                if (m.matches()) {
                    int count = m.groupCount();
                    System.out.format("count = %d\n", count);
                    for (int i = 1; i <= count; i++) {
                        System.out.format("group: %s\n", m.group(i));
                    }
                }
            }
        } catch (IOException e) {
            ;
        }
    }
    
    public static void main(String argv[]) {
        MyRegex re = new MyRegex();
        if (argv.length != 1) {
            System.err.println("need one argument. regex-pattern");
            System.exit(0);
        }
        re.doit(argv[0]);
    }
}

次はJakartaのregexpのサンプルコードです。動作は同じです。

// jakarta regexp test
import java.io.*;
import java.util.*;
import org.apache.regexp.*;

public class MyRegexp {
    public void doit(String pattern) {
        RE regex = new RE(pattern);

        BufferedReader fin = new BufferedReader(new InputStreamReader(System.in));
        try {
            while (true) {
                System.out.println("input any text");
                String s = fin.readLine();

                if (regex.match(s)) {
                    int count = regex.getParenCount();
                    System.out.format("count = %d\n", count);
                    for (int i = 1; i < count; i++) {
                        System.out.format("group: %s\n", regex.getParen(i));
                    }
                }
            }
        } catch (IOException e) {
            ;
        }
    }
    
    public static void main(String argv[]) {
        MyRegexp re = new MyRegexp();
        if (argv.length != 1) {
            System.err.println("need one argument. regex-pattern");
            System.exit(0);
        }
        re.doit(argv[0]);
    }
}

どちらも実装はNFAです。 「詳説 正規表現」ではNFAとDFAを見分けられる(可能性が高い)パターン例が載っています。 NFAだとバックトラックの嵐で異常に時間がかかるのに対し、DFAではすぐに終わるパターンです。

次のようなパターンが載っています。

  • 正規表現パターン: X(.+)+X
  • 入力テキスト: =XX===========================================================

実装がNFAであれば、無限に近いぐらいCPUが占有される(可能性が高い)、と書かれています。

まずperl, sed, grepで確認してみましたが、どれもすぐに終わります。perlとsedは刺さっても良さそうなものですが。何か細工があるのでしょうか。

Emacsを試すと、見事に刺さりました(isearch-forward-regexp)。

次のPythonも試してみました。これも刺さりました。

#!/usr/bin/python
import re
input = '=XX=========================================================================='
m = re.compile('X(.+)+X').search(input)
print input[m.start(1):m.end(1)]

さて、Javaの番です。 java.util.regexは、すぐに返ってきました。実装はNFAのはずですが(ソースを見て確認済み)、回避しています。さすが、我らがJavaです。

しかし、Jakartaのregexpは刺さりました。そんなものです。

The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/inoue/java-regex/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.