PGBox
P
G
Box

メッセージフォーマット

フォーマットのメニューへ戻る



使用した環境
JDK 6 Update 11

文字列の特定位置などを置き換えるフォーマットを行います。

java.text.MessageFormatを使用します。
テンプレート文字列の特定の位置に、動的な文字列をセットしたい場合に使用します。

import java.text.MessageFormat;

public class Main {
    public static void main(String[] args) throws Exception {
        MessageFormat format = new MessageFormat("{0}をカートに追加しました。現在、カートの中には{1}個の商品が入っています。");

        String[] messageArgs = new String[]{"電動ハブラシ", "3"};

        String result = format.format(messageArgs);

        System.out.println(result);
    }
}


結果は以下のようになります。
電動ハブラシをカートに追加しました。現在、カートの中には3個の商品が入っています。

java.text.MessageFormatのコンストラクタにテンプレート文字列を指定します。
{0}や{1}といった文字列は、置き換え用の目印文字列となります。この番号はサンプル中では[messageArgs]の配列のインデックスに該当します。



また、フォーマット文字列の通りの形式の文字列である場合、その文字列の中から、{0}や{1}に該当する文字列を取得(パーズ)する事も可能です。

import java.text.MessageFormat;

public class Main {
    public static void main(String[] args) throws Exception {
        String str = "電動ハブラシをカートに追加しました。現在、カートの中には3個の商品が入っています。";

        MessageFormat format = new MessageFormat("{0}をカートに追加しました。現在、カートの中には{1}個の商品が入っています。");

        Object[] messageArgs = format.parse(str);

        for (Object messageArg : messageArgs) {
            System.out.println(messageArg);
        }
    }
}


結果は以下のようになります。
電動ハブラシ
3

本格的な構文解析は正規表現などを使用して行う事になりますが、例えばログの中から特定の文字のみを抜き取るなどの
ちょっとした解析であれば、MessageFormat#parseを使用すると、substringやindexofを使用せずに、非常に簡単なソースで目的を達成する事が出来ます。



試しに、Apacheのアクセスログからhtmlページごとのアクセス数を集計する簡単なプログラムを作ってみます。
以下はApache2.2のデフォルト設定のaccess.logの内容の抜粋になります。
127.0.0.1 - - [15/Jul/2009:22:48:11 +0900] "GET /ref/java/core/format/message.html HTTP/1.1" 200 5642
127.0.0.1 - - [15/Jul/2009:22:48:11 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:48:11 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:48:11 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:48:53 +0900] "GET /ref/java/core/format/message.html HTTP/1.1" 200 5645
127.0.0.1 - - [15/Jul/2009:22:48:53 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:48:53 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:48:53 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:49:54 +0900] "GET /ref/java/core/format/num.html HTTP/1.1" 200 5178
127.0.0.1 - - [15/Jul/2009:22:49:54 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:49:54 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:49:54 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:49:55 +0900] "GET /ref/java/core/format/num.html HTTP/1.1" 200 5178
127.0.0.1 - - [15/Jul/2009:22:49:55 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:49:55 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:49:55 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:49:56 +0900] "GET /ref/java/core/format/num.html HTTP/1.1" 200 5178
127.0.0.1 - - [15/Jul/2009:22:49:56 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:49:56 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:49:56 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:49:58 +0900] "GET /ref/java/core/format/date.html HTTP/1.1" 200 7525
127.0.0.1 - - [15/Jul/2009:22:49:58 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:49:58 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:49:58 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:50:01 +0900] "GET /ref/java/core/format/num.html HTTP/1.1" 200 5178
127.0.0.1 - - [15/Jul/2009:22:50:01 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:50:01 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:50:01 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:50:03 +0900] "GET /ref/java/core/format/message.html HTTP/1.1" 200 5645
127.0.0.1 - - [15/Jul/2009:22:50:03 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:50:03 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:50:03 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /ref/java/core/format/message.html HTTP/1.1" 200 5645
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /ref/java/core/format/message.html HTTP/1.1" 200 5645
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:50:04 +0900] "GET /images/logo.png HTTP/1.1" 200 19919
127.0.0.1 - - [15/Jul/2009:22:50:06 +0900] "GET /ref/java/core/format/num.html HTTP/1.1" 200 5178
127.0.0.1 - - [15/Jul/2009:22:50:06 +0900] "GET /style.css HTTP/1.1" 200 2820
127.0.0.1 - - [15/Jul/2009:22:50:06 +0900] "GET /images/categoryLine.png HTTP/1.1" 200 228
127.0.0.1 - - [15/Jul/2009:22:50:06 +0900] "GET /images/logo.png HTTP/1.1" 200 19919


これに対し、以下のような解析プログラムを作成します。
htmlファイルへのアクセスを集計したいので、画像ファイルやcssファイルへのアクセスは集計から除外しています。
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

public class Main {
    
    public static void main(String[] args) throws Exception {
        
        // アクセスログのフォーマット
        MessageFormat format = new MessageFormat("{0} - [{1}] ¥"GET {2} {3}");
        
        // ページ別のアクセス数を保持するマップ Map<URL, アクセス数>
        Map<String, Integer> accessCount = new HashMap<String, Integer>();
        
        BufferedReader in = null;
        try {
            // access.logの読み込み
            in = new BufferedReader(new InputStreamReader(new FileInputStream("【access.logのパス】")));
            
            String line = null;
            while ((line = in.readLine()) != null) {
                Object[] arr = format.parse(line);
                String url = (String) arr[2];
                
                // URLの末尾(ファイル拡張子)が.htmlでない場合は対象外とする。(画像ファイルやcssは対象外)
                if (!url.endsWith(".html")) continue;
                
                // URLに対するアクセス数を取得し、加算
                Integer count = accessCount.get(url);
                if (count == null) count = 0;
                
                accessCount.put(url, count + 1);
            }
            
        } finally {
            try { in.close(); } catch (Exception e) {}
        }
        
        // 表示
        for (String url : accessCount.keySet()) {
            System.out.println(url + " → " + accessCount.get(url) + "アクセス");
        }
        
        
    }
    
}


結果は以下のようになります。
/ref/java/core/format/num.html → 5アクセス
/ref/java/core/format/date.html → 1アクセス
/ref/java/core/format/message.html → 5アクセス


上記は、簡単な事しかできないプログラムではありますが、substringやindexofで、複雑な事をせずに構文解析が行えている事が分かると思います。
正規表現を使用しても、少ないステップ数でプログラムの作成は可能ですが、java.text.MessageFormatのフォーマット文字列の方が、ぱっと見が分かりやすいので、簡単なログ解析などの場合はMessageFormatを使用すると手軽に解析が行えます。






フォーマットのメニューへ戻る