• Showing Page History #90090
  • Showing Page History #90091

Show page source of howToUse #90092

= JAutoRegexerの使い方 =
== はじめに ==
JAutoRegexerの実行エンジンの実態は「org.dyndns.nuda.tools.regex.RegexProcessor」です。[[BR]]
RegexProcessorクラスのprocessメソッドで正規表現の解析を行います。

processメソッドのシグニチャは以下の通りです。[[BR]]
{{{ code java
public List<T> process(String source, Class<T> regexBean)
}}}

型Tはsource引数に指定された文字列(正規表現で解析を行う文字列)の解析結果が格納されるクラスです。[[BR]]

解析結果は上記シグニチャの通り、型Tのリスト型で帰ります。[[BR]]

== RegexBean ==
JAutoRegexerで正規表現解析結果のマッピングに用いられるJavaBeansは厳密な意味でのJavaBeansではありません。[[BR]]
本来のJavaBeansは...
 * private なプロパティを
 * public なgetter/setter を用いてカプセル化したものであり
 * getter/setterのメソッド名はプロパティ名のキャメルケース記法を用いる

ですが、JAutoRegexerのそれは...
 * publicなプロパティをもつ

この一点です。

これを「RegexBean」と呼んでいます。

以下は、RegexBeanのサンプルです。
{{{ code java
package org.dyndns.nuda.tools.regex;

import org.dyndns.nuda.tools.regex.annotation.Regex;
import org.dyndns.nuda.tools.regex.annotation.RegexItem;

@Regex(pattern = "(.+?):(.+?)://(.+?):(.+?)/(.+)")
public class ConStrRegexBean {
	@RegexItem(groupIndex = 1)
	public String	coreName;
	
	@RegexItem(groupIndex = 2)
	public String	subProtocol;
	
	@RegexItem(groupIndex = 3)
	public String	host;
	
	@RegexItem(groupIndex = 4)
	public String	port;
	
	@RegexItem(groupIndex = 5)
	public String	schemeName;
	
	@Override
	public String toString() {
		return "ConStrRegexBean [coreName=" + this.coreName + ", subProtocol="
				+ this.subProtocol + ", host=" + this.host + ", port="
				+ this.port + ", schemeName=" + this.schemeName + "]";
	}
	
}
}}}

上記RegexBeanは
 * クラスアノテーションとして「@Regex」
 * フィールドアノテーションとして「@RegexItem」
が付加されています。

@RegexアノテーションはJAutoRegexerエンジンに対して「どのようにテキストコンテンツを解析するのか」の指示を出すために用いられます。
通常は「pattern要素」に正規表現文字列を指定して用います。

@RegexItemアノテーションは@Regexアノテーションで指定した正規表現の解析結果をどのように展開(マッピング)するのかを指定します。
「groupIndex要素」がそのまま正規表現グループのインデックスとなります。

例えば、上記RegexBeanを用いて
{{{ code java
	/**
	 * 再帰的正規表現解析なしの場合に解析が成功することを確認する
	 */
	@Test
	public void testProcess() {
		String testSource = "jdbc:mysql://192.168.0.1:3306/testdb";
		RegexProcessor p = new RegexProcessor();
		List<ConStrRegexBean> resultList = p.process(testSource,
				ConStrRegexBean.class);
		
		if (resultList.size() == 0) {
			Assert.fail();
		}
		
		ConStrRegexBean bean = resultList.get(0);
		Assert.assertEquals(bean.toString(), "jdbc", bean.coreName);
		Assert.assertEquals(bean.toString(), "mysql", bean.subProtocol);
		Assert.assertEquals(bean.toString(), "192.168.0.1", bean.host);
		Assert.assertEquals(bean.toString(), "3306", bean.port);
		Assert.assertEquals(bean.toString(), "testdb", bean.schemeName);
		
	}
}}}

とすれば、リストの0番目のRegexBean(ConStrRegexBean)に「jdbc:mysql://192.168.0.1:3306/testdb」が分解されて格納されます。

※上のサンプルコードはJAutoRegexerのテストケースから一部を抜き出したものです。

== 再帰展開(Recursive Mappings) ==
JAutoRegexerの特徴は、RegexBeanのプロパティとしてRegexBeanを指定できる点です。
以下のサンプルコードをご覧ください。

ConStrRegexBean02.java
{{{ code java
package org.dyndns.nuda.tools.regex;

import java.util.List;

import org.dyndns.nuda.tools.regex.annotation.Regex;
import org.dyndns.nuda.tools.regex.annotation.RegexItem;

@Regex(pattern = "(.+?):(.+?)://(.+?):(.+?)/(.+)")
public class ConStrRegexBean02 {
	@RegexItem(groupIndex = 1)
	public String				coreName;
	
	@RegexItem(groupIndex = 2)
	public String				subProtocol;
	
	@RegexItem(groupIndex = 3)
	public List<HostRegexBean>	host;
	
	@RegexItem(groupIndex = 4)
	public String				port;
	
	@RegexItem(groupIndex = 5)
	public String				schemeName;
	
	@Override
	public String toString() {
		return "ConStrRegexBean02 [coreName=" + this.coreName
				+ ", subProtocol=" + this.subProtocol + ", host=" + this.host
				+ ", port=" + this.port + ", schemeName=" + this.schemeName
				+ "]";
	}
	
}
}}}

HostRegexBean.java
{{{ code java
package org.dyndns.nuda.tools.regex;

import org.dyndns.nuda.tools.regex.annotation.Regex;
import org.dyndns.nuda.tools.regex.annotation.RegexItem;

@Regex(pattern = "(.+?)\\.(.+?)\\.(.+?)\\.(.+?)")
public class HostRegexBean {
	@RegexItem(groupIndex = 1)
	public String	segment01;
	
	@RegexItem(groupIndex = 2)
	public String	segment02;
	
	@RegexItem(groupIndex = 3)
	public String	segment03;
	
	@RegexItem(groupIndex = 4)
	public String	segment04;
	
	@Override
	public String toString() {
		return "HostRegexBean [segment01=" + this.segment01 + ", segment02="
				+ this.segment02 + ", segment03=" + this.segment03
				+ ", segment04=" + this.segment04 + "]";
	}
	
}

}}}

ConStrRegexBean02クラスのhostフィールドがHostRegexBean型のリストで指定されています。

このRegexBeanを用いたサンプルコードを以下に示します。

{{{ code java
	/**
	 * 再帰的正規表現解析ありの場合に解析が成功することを確認する
	 */
	@Test
	public void testProcess02() {
		String testSource = "jdbc:mysql://192.168.0.1:3306/testdb";
		RegexProcessor p = new RegexProcessor();
		List<ConStrRegexBean02> resultList = p.process(testSource,
				ConStrRegexBean02.class);
		
		if (resultList.size() == 0) {
			Assert.fail();
		}
		
		ConStrRegexBean02 bean = resultList.get(0);
		Assert.assertEquals(bean.toString(), "jdbc", bean.coreName);
		Assert.assertEquals(bean.toString(), "mysql", bean.subProtocol);
		
		Assert.assertEquals(bean.toString(), "3306", bean.port);
		Assert.assertEquals(bean.toString(), "testdb", bean.schemeName);
		
		List<HostRegexBean> host = bean.host;
		
		if (host.size() == 0) {
			Assert.fail();
		}
		
		HostRegexBean hostRegexBean = host.get(0);
		Assert.assertEquals(host.toString(), "192", hostRegexBean.segment01);
		Assert.assertEquals(host.toString(), "168", hostRegexBean.segment02);
		Assert.assertEquals(host.toString(), "0", hostRegexBean.segment03);
		Assert.assertEquals(host.toString(), "1", hostRegexBean.segment04);
	}
}}}

最初のサンプルコード(ConStrRegexBeanを用いたもの)では、単に解析結果をRegexBeanに展開して終わりでしたが、今回のサンプルコードは少々違います。

もうお気づきかと思われますが、RegexBeanのプロパティにRegexBeanのリストが指定された場合は、再帰的に正規表現を解析します。
上記コードの場合はhostフィールドに展開されるはずだった"192.168.0.1"という文字列がHostRegexBeanによって解析され展開されます。

具体的には「192, 168, 0, 1」の文字列が「segment01, segment02, segment03, segment04」にそれぞれ展開されます。

この再帰の回数に制限はありません。
JAutoRegexerは、現在のコンテキストで「解析する必要がある限り」根こそぎRegexBeanへの展開を行います。