JAutoRegexerの使い方

はじめに

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

processメソッドのシグニチャは以下の通りです。

  1. public List<T> process(String source, Class<T> regexBeanClass)

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

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

RegexBean

JAutoRegexerで正規表現解析結果のマッピングに用いられるJavaBeansは厳密な意味でのJavaBeansではありません。
本来のJavaBeansは...

  • private なプロパティを
  • public なgetter/setter を用いてカプセル化したものであり
  • getter/setterのメソッド名はプロパティ名のキャメルケース記法を用いる

ですが、JAutoRegexerのそれは...

  • publicなプロパティをもつ

この一点です。

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

以下は、RegexBeanのサンプルです。

  1. package org.dyndns.nuda.tools.regex;
  2. import org.dyndns.nuda.tools.regex.annotation.Regex;
  3. import org.dyndns.nuda.tools.regex.annotation.RegexItem;
  4. @Regex(pattern = "(.+?):(.+?)://(.+?):(.+?)/(.+)")
  5. public class ConStrRegexBean {
  6. @RegexItem(groupIndex = 1)
  7. public String coreName;
  8. @RegexItem(groupIndex = 2)
  9. public String subProtocol;
  10. @RegexItem(groupIndex = 3)
  11. public String host;
  12. @RegexItem(groupIndex = 4)
  13. public String port;
  14. @RegexItem(groupIndex = 5)
  15. public String schemeName;
  16. @Override
  17. public String toString() {
  18. return "ConStrRegexBean [coreName=" + this.coreName + ", subProtocol="
  19. + this.subProtocol + ", host=" + this.host + ", port="
  20. + this.port + ", schemeName=" + this.schemeName + "]";
  21. }
  22. }

上記RegexBean

  • クラスアノテーションとして「@Regex」
  • フィールドアノテーションとして「@RegexItem

が付加されています。

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

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

例えば、上記RegexBeanを用いて

  1. /**
  2. * 再帰的正規表現解析なしの場合に解析が成功することを確認する
  3. */
  4. @Test
  5. public void testProcess() {
  6. String testSource = "jdbc:mysql://192.168.0.1:3306/testdb";
  7. RegexProcessor p = new RegexProcessor();
  8. List<ConStrRegexBean> resultList = p.process(testSource,
  9. ConStrRegexBean.class);
  10. if (resultList.size() == 0) {
  11. Assert.fail();
  12. }
  13. ConStrRegexBean bean = resultList.get(0);
  14. Assert.assertEquals(bean.toString(), "jdbc", bean.coreName);
  15. Assert.assertEquals(bean.toString(), "mysql", bean.subProtocol);
  16. Assert.assertEquals(bean.toString(), "192.168.0.1", bean.host);
  17. Assert.assertEquals(bean.toString(), "3306", bean.port);
  18. Assert.assertEquals(bean.toString(), "testdb", bean.schemeName);
  19. }

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

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

再帰展開(Recursive Mappings)

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

ConStrRegexBean02.java

  1. package org.dyndns.nuda.tools.regex;
  2. import java.util.List;
  3. import org.dyndns.nuda.tools.regex.annotation.Regex;
  4. import org.dyndns.nuda.tools.regex.annotation.RegexItem;
  5. @Regex(pattern = "(.+?):(.+?)://(.+?):(.+?)/(.+)")
  6. public class ConStrRegexBean02 {
  7. @RegexItem(groupIndex = 1)
  8. public String coreName;
  9. @RegexItem(groupIndex = 2)
  10. public String subProtocol;
  11. @RegexItem(groupIndex = 3)
  12. public List<HostRegexBean> host;
  13. @RegexItem(groupIndex = 4)
  14. public String port;
  15. @RegexItem(groupIndex = 5)
  16. public String schemeName;
  17. @Override
  18. public String toString() {
  19. return "ConStrRegexBean02 [coreName=" + this.coreName
  20. + ", subProtocol=" + this.subProtocol + ", host=" + this.host
  21. + ", port=" + this.port + ", schemeName=" + this.schemeName
  22. + "]";
  23. }
  24. }

HostRegexBean.java

  1. package org.dyndns.nuda.tools.regex;
  2. import org.dyndns.nuda.tools.regex.annotation.Regex;
  3. import org.dyndns.nuda.tools.regex.annotation.RegexItem;
  4. @Regex(pattern = "(.+?)\\.(.+?)\\.(.+?)\\.(.+?)")
  5. public class HostRegexBean {
  6. @RegexItem(groupIndex = 1)
  7. public String segment01;
  8. @RegexItem(groupIndex = 2)
  9. public String segment02;
  10. @RegexItem(groupIndex = 3)
  11. public String segment03;
  12. @RegexItem(groupIndex = 4)
  13. public String segment04;
  14. @Override
  15. public String toString() {
  16. return "HostRegexBean [segment01=" + this.segment01 + ", segment02="
  17. + this.segment02 + ", segment03=" + this.segment03
  18. + ", segment04=" + this.segment04 + "]";
  19. }
  20. }

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

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

  1. /**
  2. * 再帰的正規表現解析ありの場合に解析が成功することを確認する
  3. */
  4. @Test
  5. public void testProcess02() {
  6. String testSource = "jdbc:mysql://192.168.0.1:3306/testdb";
  7. RegexProcessor p = new RegexProcessor();
  8. List<ConStrRegexBean02> resultList = p.process(testSource,
  9. ConStrRegexBean02.class);
  10. if (resultList.size() == 0) {
  11. Assert.fail();
  12. }
  13. ConStrRegexBean02 bean = resultList.get(0);
  14. Assert.assertEquals(bean.toString(), "jdbc", bean.coreName);
  15. Assert.assertEquals(bean.toString(), "mysql", bean.subProtocol);
  16. Assert.assertEquals(bean.toString(), "3306", bean.port);
  17. Assert.assertEquals(bean.toString(), "testdb", bean.schemeName);
  18. List<HostRegexBean> host = bean.host;
  19. if (host.size() == 0) {
  20. Assert.fail();
  21. }
  22. HostRegexBean hostRegexBean = host.get(0);
  23. Assert.assertEquals(host.toString(), "192", hostRegexBean.segment01);
  24. Assert.assertEquals(host.toString(), "168", hostRegexBean.segment02);
  25. Assert.assertEquals(host.toString(), "0", hostRegexBean.segment03);
  26. Assert.assertEquals(host.toString(), "1", hostRegexBean.segment04);
  27. }

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

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

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

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