如何在 java中 使用 Antlr4 处理文本

需求:文件中的每一行数据都以 ”~@~“ 分隔开,读取文件,将对应属性保存到对象的对应属性。

文本:

01~@~0101~@~AE040802~@~bo123~@~BO20141011~@~AC1234~@~2017-11-11~@~0~@~0~@~1.2~@~10000000.00~@~20000.22~@~2019-10-10~@~2020-10-10~@~365
C

对应对象:

package com.xmlParsing.model;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 子公司借款-计息.
 *
 * @author ch
 * @version 1.0.0
 * @since 1.0.0
 *
 * Created at 2019-07-13 11:31
 */
public class CapInterestPacket {

  /*  业务一级类别 Y
   * 01 资金投资业务  */
  private String businessClass;

  /*  业务二级类别 Y
   * 0101 资金投资业务-子公司借款 */
  private String businessClassTwo;

  /*  业务事件类型 Y
   * AE040802 子公司借款-计息 */
  private String eventType;

  /*  核算分类 Y  */
  private String acctClass;

  /*  批次号   */
  private String batchNo;

  /*  借款协议编号 Y 子公司借款记录唯一标识 */
  private String agreementSerialNo;

  /*  业务发生日期 N  */
  private Date businessDate;

  /*  是否已封包 Y 0:否、1:是;*/
  private Integer isPackaged;

  /*  是否已转让 Y 0:否、1:是;*/
  private Integer isTransfered;

  /*  借款余额 Y  */
  private BigDecimal borrowAmount;

  /*  借款利率 N */
  private BigDecimal loanRate;

  /*  本次计息金额 Y  */
  private BigDecimal enLocalInterest;

  /*  匡息开始日 Y */
  private Date startDate;

  /*  匡息终止日 Y */
  private Date endDate;

  /*  匡算天数 N  */
  private Integer calDays;

  /* 状态码 */
  private String code;

  /* 信息描述 */
  private String desc;

  public String getBusinessClass() {
    return businessClass;
  }

  public void setBusinessClass(String businessClass) {
    this.businessClass = businessClass;
  }

  public String getBusinessClassTwo() {
    return businessClassTwo;
  }

  public void setBusinessClassTwo(String businessClassTwo) {
    this.businessClassTwo = businessClassTwo;
  }

  public String getEventType() {
    return eventType;
  }

  public void setEventType(String eventType) {
    this.eventType = eventType;
  }

  public String getAcctClass() {
    return acctClass;
  }

  public void setAcctClass(String acctClass) {
    this.acctClass = acctClass;
  }

  public String getBatchNo() {
    return batchNo;
  }

  public void setBatchNo(String batchNo) {
    this.batchNo = batchNo;
  }

  public String getAgreementSerialNo() {
    return agreementSerialNo;
  }

  public void setAgreementSerialNo(String agreementSerialNo) {
    this.agreementSerialNo = agreementSerialNo;
  }

  public Date getBusinessDate() {
    return businessDate;
  }

  public void setBusinessDate(Date businessDate) {
    this.businessDate = businessDate;
  }

  public Integer getIsPackaged() {
    return isPackaged;
  }

  public void setIsPackaged(Integer isPackaged) {
    this.isPackaged = isPackaged;
  }

  public Integer getIsTransfered() {
    return isTransfered;
  }

  public void setIsTransfered(Integer isTransfered) {
    this.isTransfered = isTransfered;
  }

  public BigDecimal getBorrowAmount() {
    return borrowAmount;
  }

  public void setBorrowAmount(BigDecimal borrowAmount) {
    this.borrowAmount = borrowAmount;
  }

  public BigDecimal getLoanRate() {
    return loanRate;
  }

  public void setLoanRate(BigDecimal loanRate) {
    this.loanRate = loanRate;
  }

  public BigDecimal getEnLocalInterest() {
    return enLocalInterest;
  }

  public void setEnLocalInterest(BigDecimal enLocalInterest) {
    this.enLocalInterest = enLocalInterest;
  }

  public Date getStartDate() {
    return startDate;
  }

  public void setStartDate(Date startDate) {
    this.startDate = startDate;
  }

  public Date getEndDate() {
    return endDate;
  }

  public void setEndDate(Date endDate) {
    this.endDate = endDate;
  }

  public Integer getCalDays() {
    return calDays;
  }

  public void setCalDays(Integer calDays) {
    this.calDays = calDays;
  }

  @Override
  public String toString() {
    return "CapInterestPacket{" +
        "businessClass='" + businessClass + '\'' +
        ", businessClassTwo='" + businessClassTwo + '\'' +
        ", eventType='" + eventType + '\'' +
        ", acctClass='" + acctClass + '\'' +
        ", batchNo='" + batchNo + '\'' +
        ", agreementSerialNo='" + agreementSerialNo + '\'' +
        ", businessDate=" + businessDate +
        ", isPackaged=" + isPackaged +
        ", isTransfered=" + isTransfered +
        ", borrowAmount=" + borrowAmount +
        ", loanRate=" + loanRate +
        ", enLocalInterest=" + enLocalInterest +
        ", startDate=" + startDate +
        ", endDate=" + endDate +
        ", calDays=" + calDays +
        ", code='" + code + '\'' +
        ", desc='" + desc + '\'' +
        '}';
  }

  public String getCode() {
    return code;
  }

  public void setCode(String code) {
    this.code = code;
  }

  public String getDesc() {
    return desc;
  }

  public void setDesc(String desc) {
    this.desc = desc;
  }

}

准备工作:

idea 下载 ANTLR V4 grammar plugin 插件

加入 maven 配置 依赖和插件

 <dependency>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4</artifactId>
	<version>4.7.2</version>
 </dependency>
	
<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
		<plugin>
			<groupId>org.antlr</groupId>
			<artifactId>antlr4-maven-plugin</artifactId>
			<version>4.3</version>
			<executions>
				<execution>
					<id>antlr</id>
					<goals>
						<goal>antlr4</goal>
					</goals>
					<phase>none</phase>
				</execution>
			</executions>
			<!--<configuration>-->
				<!--<outputDirectory>src/test/java</outputDirectory>-->
				<!--<listener>true</listener>-->
				<!--<treatWarningsAsErrors>true</treatWarningsAsErrors>-->
			<!--</configuration>-->
		</plugin>
	</plugins>
</build>

新建.g4 文件并配置

规则可以自己定义

grammar Dsl;   //定义规则文件grammar

//options{filter=true;}  //指定 filter 选项

// 抽取器辅助词法定义
txtFrg :
  businessClass'~@~' businessClasstwo  '~@~' eventType  '~@~' acctClass '~@~' batchNo '~@~'agreementSerialNo  '~@~' businessDate '~@~' isPackaged '~@~' isTransfered  '~@~' borrowAmount  '~@~' loanRate '~@~' enlocalInterest '~@~' startDate '~@~' endDate '~@~' calDays;


businessClass
  :BUSINESSCLASS;

businessClasstwo
  :BUSINESSCLASSTWO;

eventType
  :EVENTTYPE;

acctClass
  :ACCTCLASS;

batchNo
  :BATCHNO;

agreementSerialNo
  :AGREEMENTSERIALNO;

businessDate
  :BUSINESSDATE;

isPackaged
  :ISPACKAGED;

isTransfered
  :ISTRANSFERED;

borrowAmount
  :BORROWAMOUNT;

loanRate
  :LOANRATE;

enlocalInterest
  :ENLOCALINTEREST;

startDate
  :STARTDATE;

endDate
  :ENDDATE;

calDays
  :CALDAYS;


fragment
// 业务一级类别.  01 资金投资业务
BUSINESSCLASS : [0-9][0-9];


// 业务二级类别.  0101 资金投资业务-子公司借款
BUSINESSCLASSTWO: [0-9]+;


// 业务时间类别. AE040802 子公司借款-计息
EVENTTYPE : [a-zA-Z][a-zA-Z][0-9]+;


// 核算分类
ACCTCLASS : [a-zA-Z][a-zA-Z][0-9]+;


// 批次号
BATCHNO : [a-zA-Z][a-zA-Z][0-9]+;


// 借款协议号
AGREEMENTSERIALNO : [a-zA-Z][a-zA-Z][0-9]+;

// 业务发生日期
BUSINESSDATE : (('19'|'20')[0-9]+)'-'([0-9][0-9])'-'(('0'|'1'|'2'|'3')[0-9]) ;


// 是否已封包
ISPACKAGED : '0'|'1' ;


// 是否已转让
ISTRANSFERED : '0'|'1';


// 借款余额
BORROWAMOUNT : [0-9]+[.][0-9]* ;


// 借款利率
LOANRATE : [0-9]+[.][0-9]* ;


// 本次计息金额
ENLOCALINTEREST : [0-9]+[.][0-9]* ;


// 匡息开始日
STARTDATE : (('19'|'20')[0-9]+)'-'([0-9][0-9])'-'(('0'|'1'|'2'|'3')[0-9]) ;


// 匡息结束日
ENDDATE : (('19'|'20')[0-9]+)'-'([0-9][0-9])'-'(('0'|'1'|'2'|'3')[0-9]) ;


// 匡息天数
CALDAYS : [0-9]+;

生成代码 

或者使用 maven 的插件来 构造

编写 main 调用规则

package com.xmlParsing;

import com.xmlParsing.model.CapInterestPacket;
import com.xmlParsing.parser.DslBaseListener;
import com.xmlParsing.parser.DslLexer;
import com.xmlParsing.parser.DslParser;
import com.xmlParsing.parser.DslParser.AcctClassContext;
import com.xmlParsing.parser.DslParser.AgreementSerialNoContext;
import com.xmlParsing.parser.DslParser.BatchNoContext;
import com.xmlParsing.parser.DslParser.BorrowAmountContext;
import com.xmlParsing.parser.DslParser.BusinessClassContext;
import com.xmlParsing.parser.DslParser.BusinessClasstwoContext;
import com.xmlParsing.parser.DslParser.BusinessDateContext;
import com.xmlParsing.parser.DslParser.CalDaysContext;
import com.xmlParsing.parser.DslParser.EndDateContext;
import com.xmlParsing.parser.DslParser.EnlocalInterestContext;
import com.xmlParsing.parser.DslParser.EventTypeContext;
import com.xmlParsing.parser.DslParser.IsPackagedContext;
import com.xmlParsing.parser.DslParser.IsTransferedContext;
import com.xmlParsing.parser.DslParser.LoanRateContext;
import com.xmlParsing.parser.DslParser.StartDateContext;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

/**
 * TODO
 *
 * @author ch
 * @version 1.0.0
 * @since 1.0.0
 *
 * Created at 2019-07-16 17:20
 */
public class AntlrTest {


  public static void main(String[] args) throws Exception {
    int len = 0;
    BufferedReader in = new BufferedReader(
        new FileReader(new File("/Users/chenhao/Desktop/xmlParsing/src/main/resources/计息.txt")));
    StringBuffer str = new StringBuffer();
    String line;
    while ((line = in.readLine()) != null) {
      if (len != 0) // 处理换行符的问题
      {
        str.append("\r\n" + line);
      } else {
        str.append(line);
      }
      len++;
    }
    in.close();
    CapInterestPacket cp = run(str.toString());
    System.out.println(str.toString());
    System.out.println(cp);


  }

  public static CapInterestPacket run(String expr) throws Exception {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    CapInterestPacket cp = new CapInterestPacket();
    //对每一个输入的字符串,构造一个 ANTLRStringStream 流 in
    ANTLRInputStream in = new ANTLRInputStream(expr);

    //用 in 构造词法分析器 lexer,词法分析的作用是产生记号
    DslLexer lexer = new DslLexer(in);

    //用词法分析器 lexer 构造一个记号流 tokens
    CommonTokenStream tokens = new CommonTokenStream(lexer);

    //再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作
    DslParser parser = new DslParser(tokens);
    //最终调用语法分析器的规则 prog,完成对表达式的验证

    parser.addParseListener(new DslBaseListener() {


      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitIsTransfered(IsTransferedContext ctx) {
        cp.setIsTransfered(Integer.valueOf(ctx.getText()));
        super.exitIsTransfered(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitBatchNo(BatchNoContext ctx) {
        cp.setBatchNo(ctx.getText());
        super.exitBatchNo(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitEnlocalInterest(EnlocalInterestContext ctx) {
        cp.setEnLocalInterest(new BigDecimal(ctx.getText()));
        super.exitEnlocalInterest(ctx);
      }


      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitCalDays(CalDaysContext ctx) {
        cp.setCalDays(Integer.valueOf(ctx.getText()));
        super.exitCalDays(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitAcctClass(AcctClassContext ctx) {
        cp.setAcctClass(ctx.getText());
        super.exitAcctClass(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitEndDate(EndDateContext ctx) throws ParseException {
        cp.setEndDate(sdf.parse(ctx.getText()));
        super.exitEndDate(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitBusinessClass(BusinessClassContext ctx) {
        cp.setBusinessClass(ctx.getText());
        super.exitBusinessClass(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitAgreementSerialNo(AgreementSerialNoContext ctx) {
        cp.setAgreementSerialNo(ctx.getText());
        super.exitAgreementSerialNo(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitEventType(EventTypeContext ctx) {
        cp.setEventType(ctx.getText());
        super.exitEventType(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitIsPackaged(IsPackagedContext ctx) {
        cp.setIsPackaged(Integer.valueOf(ctx.getText()));
        super.exitIsPackaged(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitBusinessDate(BusinessDateContext ctx) throws ParseException {
        cp.setBusinessDate(sdf.parse(ctx.getText()));
        super.exitBusinessDate(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitBorrowAmount(BorrowAmountContext ctx) {
        cp.setBorrowAmount(new BigDecimal(ctx.getText()));
        super.exitBorrowAmount(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitBusinessClasstwo(BusinessClasstwoContext ctx) {
        cp.setBusinessClassTwo(ctx.getText());
        super.exitBusinessClasstwo(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitLoanRate(LoanRateContext ctx) {
        cp.setLoanRate(new BigDecimal(ctx.getText()));
        super.exitLoanRate(ctx);
      }

      // 在读取每一个匹配规则的的属性的时候 将内容插入对象的属性
      @Override
      public void exitStartDate(StartDateContext ctx) throws ParseException {

        cp.setStartDate(sdf.parse(ctx.getText()));
        super.exitStartDate(ctx);
      }

    });

    parser.txtFrg();
    return cp;

  }


}

调用 main 方法 输出结果:

line 1:23 mismatched input 'bo123' expecting ACCTCLASS
line 1:31 mismatched input 'BO20141011' expecting BATCHNO
line 1:44 mismatched input 'AC1234' expecting AGREEMENTSERIALNO
line 1:66 mismatched input '0' expecting ISPACKAGED
line 1:70 mismatched input '0' expecting ISTRANSFERED
line 1:80 mismatched input '10000000.00' expecting LOANRATE
line 1:94 mismatched input '20000.22' expecting ENLOCALINTEREST
line 1:105 mismatched input '2019-10-10' expecting STARTDATE
line 1:118 mismatched input '2020-10-10' expecting ENDDATE
line 1:131 mismatched input '365' expecting CALDAYS
01~@~0101~@~AE040802~@~bo123~@~BO20141011~@~AC1234~@~2017-11-11~@~0~@~0~@~1.2~@~10000000.00~@~20000.22~@~2019-10-10~@~2020-10-10~@~365
CapInterestPacket{businessClass='01', businessClassTwo='0101', eventType='AE040802', acctClass='bo123', batchNo='BO20141011', agreementSerialNo='AC1234', businessDate=Sat Nov 11 00:00:00 CST 2017, isPackaged=0, isTransfered=0, borrowAmount=1.2, loanRate=10000000.00, enLocalInterest=20000.22, startDate=Thu Oct 10 00:00:00 CST 2019, endDate=Sat Oct 10 00:00:00 CST 2020, calDays=365, code='null', desc='null'}

不管是否匹配,都会调用 exit 方法,所以直接set属性即可。

参考链接 https://www.ibm.com/developerworks/cn/java/j-lo-antlrtext/#ibm-pcon

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值