Java は J2SE 1.4 まで、API レベルでテキスト処理は苦手でした。J2ME に至ってはかなり低レベルの処理しかできません。
また JDK 1.1 以降でも java.text.* API で日付の解析などができるようになったもののちょっとした字句解析をするためにはいろいろ面倒な処理を強いられました。
そこで少しでも簡単に字句解析ができるように、J2ME CDC から J2SE まで広範囲に使えるライブラリを作ってみました。
http://cappuccino.jp/keisuken/java/lex/lex-0.4.2.tar.gz からダウンロードできます。
build.xml Ant build file. readme.txt readme text file. license.txt License file. docs/specification.html Specification and reference manual (this file) docs/api/ Lex API reference manual src/ Lex source. samples/ Sample source files. lib/tablelayout.jar Lex package file.
以下の環境で動作します。基本的に JDK 1.2 以上の API を使っていませんので殆どの環境で動作させられるでしょう。
| ランタイム | JDK 1.1/J2ME CDC 以上 |
|---|---|
| OS | JDK 1.1/J2ME CDC 以上が動作する OS |
| 確認環境 | Windows 2000, J2SDK 1.4.1_02 Mac OS X, J2SDK 1.4.1_01 |
${lex_home}/lib/lex.jar を CLASSPATH に加えて下さい。それでこのライブラリは使用できます。
必要なランタイムとツールは以下のとおりです。
| ランタイム | J2SDK 1.3.x 以上 |
|---|---|
| ツール | Apache Ant 1.5.x |
JDK 1.3.x 以上 と Ant 1.5.x をインストールしたのち、${lex_home} ディレクトリに移動して、ant を実行してください。
bash-2.05b$ cd lex
bash-2.05b$ ant
Buildfile: build.xml
compile:
[mkdir] Created dir: C:\home\keisuken\lex\classes
...
この例では、Windows 2000 上の Cygwin で実行しています。
基本的に正規表現を Composite Pattern 風にツリーオブジェクトとして生成するだけで字句解析が行えるようになっています。ここでいう正規表現は、選択('|')、連接、繰返し('*')であり、これらの組み合わせにより文字列の解析を行います。
実装クラスを以下の通りです。
| クラス | 説明 | 備考 |
|---|---|---|
| Lex | 抽象字句解析器 | match(マッチ)以外に、find(検索), split(分割) などのメソッドも実装されています。 独自の字句解析器を作るときにはこのクラスを継承し、コンストラクタと _m メソッドを実装します。 |
| LexResult | 解析結果 | マッチした字句の位置やマッチ文字列を返します |
| LexReader | 字句 Reader | 字句解析専用の Reader |
| Alter | 選択字句解析器 | 正規表現で言う '|' に相当 |
| Concat | 連接字句解析器 | 正規表現で言う連接 |
| Power | 繰返し字句解析器 | 正規表現で言う '*' に相当、'+' なども使える |
| Char | 文字クラス字句解析器 | 正規表現で言う '[...]' に相当 |
| Word | 固定語字句解析器 | 固定(Const.)な文字列の字句解析を行う |
| Space/JSpace | 空白字句解析器 | Unicode や Java の空白のマッチングを行う、'*', '+' などの指定も可能 |
| Ident/JIdent | 識別文字列解析器 | Unicode や Java の識別子のマッチングを行う |
正規表現ツリーを生成するには、以下のようにします。
sp ::= JSpace tagStart ::= '<%=' tagName ::= JIdent tagEnd ::= '%>' tag ::= tagStart sp tagName sp tagEnd
Lex sp = new JSpace(JSpace.ASTER, null);
Lex tagStart = new Word("<%=", null);
Lex tagName = new JIdent(null);
Lex tagEnd = new Word("%>", null);
Lex tag = new Concat(
new Lex[] {tagStart, sp, tagName, sp, tagEnd}, null);
String text = "Date: <%= date %>.";
LexReader reader = new LexReader(text);
LexResult result = tag.find(reader);
if(result != null) {
System.out.println("マッチした文字列 = " + result.str());
} else {
System.out.println("マッチしませんでした");
}
マッチした文字列 = <%= date %>
ライセンスは MIT license に準じます。
The MIT License
Copyright (c) 2001-2005 NISHIMOTO Keisuke
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
何か質問・要望などありましたら keisuken atmark cappuccino.ne.jp 宛てにメールをください。
低レベルな API なため、このライブラリだけでは凝ったプログラミングはできません。基本的な字句解析器しか実装していない為、専用の字句解析器が欲しくなるかもしれません。
その場合も Super Class である Lex を継承すれば割と簡単に実装できることでしょう。またこのライブラリだけでも CSV Parser を作ることも可能です。
そういった簡単な設定ファイルなどを解析する Parser を作るときにこのライブラリは重宝すると思います。
Date: <%= date %>, Members: <%= members %>.
Text: "Date: " Tag: [date] Text: ", Members: " Tag: [members] Text: "."
1234,5678 , 1234 ,5678 ,1234, 5678 ,
"1234" "5678" "" "1234" "5678" "" "1234" "5678" ""
Date: <%= date %>, Members: <%= members %>.
<%= date %> <%= members %>
Date: %%date%% Members: %% repeat : members %% %% id %%. %%name%% %%endrepeat%%
Text: "Date: " Tag: [date] Text: "Members:" Tag: [repeat][members] Text: " " Tag: [id] Text: ". " Tag: [name] Tag: [endrepeat]