You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在空行处关闭ANTLR词法模式?

ANTLR词法分析器实现:捕获含换行文本块,遇空行退出模式

问题背景

输入文件包含多种以空行分隔的数据块,需为每个块启用对应词法模式处理,其中部分块需要捕获包含换行符在内的所有内容。但现有词法规则无法实现:捕获包含单个换行的所有字符,同时在遇到连续换行(空行)时退出当前模式,尝试通过指定允许字符并排除单个字符的方式未能达成需求。

初始实现代码

初始词法分析器语法BlocksLexer.g4

lexer grammar BlocksLexer ;

BLK01 : 'BLOCK01' ;
BLK02 : 'BLOCK02' ;
BLK03 : 'BLOCK03' ;
BLK04 : 'BLOCK04' -> pushMode(ALLTEXT) ;
BLK05 : 'BLOCK05' ;

KEYPARPAR : 'param' ;
KEYPARPRO1 : 'property1' ;
KEYPARPRO2 : 'property2' ;
KEYPARSIZ : 'size' ;
KEYPARWGT : 'weight' ;
KEYPARPAG : 'pages' ;
KEYPARCNT : 'count' ;
KEYPARCUR : 'currency' ;
KEYPARVAL : 'value' ;

ARROW : '->' ;
CHRAMP : '&' ;
CHRAPOSDOU : '"' ;
CHRAPOSSIN : '\'' ;
CHRCOLON : ':' ;
CHRCOMMA : ',' ;
CHRDOT : '.' ;
CHREQUAL : '=' ;
CHRSEMICOLON : ';' ;

ID : [A-Z][A-Z0-9]+ ;
NUM : [0-9]+ ;
STRING : '"' (~'\r'|~'\n')*? '"' ;
NAM : [A-Z][a-z]+ ;
NAMVAR : [a-z][a-z]* ;
NEWLINE : ('\r'? '\n'|'\r') -> channel(HIDDEN) ;
WS : [ \t]+ -> skip ;

// Parsing novel
mode ALLTEXT;
NOVEL         : ~[#]+ ;
CLOSE_ALLTEXT : '#' -> popMode ;

初始解析器语法BlocksParser.g4

parser grammar BlocksParser ;

options {
  tokenVocab = BlocksLexer ;
}

file : blk01 blk02 blk03 blk04+ blk05 ;

blk01 : blk01Who blk01What ;
blk01Who : ARROW BLK01 ;
blk01What : ID assign ;

blk02 : blk02Who blk02What ;
blk02Who : ARROW BLK02 ;
blk02What : ID assign  assign* ;

blk03 : blk03Who blk03What+ ;
blk03Who : ARROW BLK03 ;
blk03What : ID assign assign* ;

blk04 : blk04Who blk04What CLOSE_ALLTEXT;
blk04Who : ARROW BLK04 ;
blk04What : NOVEL ;

blk05 : blk05Who blk05What+ ;
blk05Who : ARROW BLK05 ;
blk05What : ID assign assign* ;

assign : param (CHRCOLON|CHREQUAL) value ;
param : KEYPARPAR|KEYPARPRO1|KEYPARPRO2|KEYPARSIZ|KEYPARWGT|KEYPARPAG|KEYPARCNT|KEYPARCUR|KEYPARVAL ;
value : STRING|NUM|var ;
var : CHRAMP NAMVAR ;

初始测试输入文件t.txt

->BLOCK01
START param=&wert

->BLOCK02
SELF property1="abc" property2="def"

->BLOCK03
ITEM1 property1:"xyz" property2:"set"
ITEM2 property1:"xyz" property2:"set"
ITEM3 property1:"xyz" property2:"set"

->BLOCK04
GOOD01 size:"2x3" weight:"23"
DOCUMENT01 pages:37
ORDER01 count:37
#

->BLOCK04
GOOD02 size:"5x6" weight:"32"
AMOUNT02 currency:"US" value:2033
#

->BLOCK04
ORDER03 count:44
DOCUMENT03 pages:24
GOOD03 size:"2x4" weight:"87"
#

->BLOCK05
GOOD0501 size:"3x7" weight:"34"
AMOUNT0501 currency:"EU" value:2025

初始实现用#作为BLOCK04的终止符演示功能,需求是改为以空行作为ALLTEXT词法模式的终止符。

解决方案

采用Kens(kaby76)的方法修改语法,实现以空行终止ALLTEXT模式的需求。

修改后词法分析器语法BlckVer2Lexer.g4

lexer grammar BlckVer2Lexer ;

tokens { NOVEL }

BLK01 : 'BLOCK01' ;
BLK02 : 'BLOCK02' ;
BLK03 : 'BLOCK03' ;
BLK04 : 'BLOCK04' -> pushMode(ALLTEXT) ;
BLK05 : 'BLOCK05' ;

KEYPARPAR : 'param' ;
KEYPARPRO1 : 'property1' ;
KEYPARPRO2 : 'property2' ;
KEYPARSIZ : 'size' ;
KEYPARWGT : 'weight' ;
KEYPARPAG : 'pages' ;
KEYPARCNT : 'count' ;
KEYPARCUR : 'currency' ;
KEYPARVAL : 'value' ;

ARROW : '->' ;
CHRAMP : '&' ;
CHRAPOSDOU : '"' ;
CHRAPOSSIN : '\'' ;
CHRCOLON : ':' ;
CHRCOMMA : ',' ;
CHRDOT : '.' ;
CHREQUAL : '=' ;
CHRSEMICOLON : ';' ;

ID : [A-Z][A-Z0-9]+ ;
NUM : [0-9]+ ;
STRING : '"' ~[\n]*? '"' ;
NAM : [A-Z][a-z]+ ;
NAMVAR : [a-z][a-z]* ;
NEWLINE : '\n' -> channel(HIDDEN) ;
WS : [ \r\t]+ -> skip ;

// Parsing novel
mode ALLTEXT;

DUMMY1 : ~[\n] -> more ;
DUMMY2 : { this.getCharPositionInLine() != 0 }? '\n' -> more ;
DUMMY3 : { this.getCharPositionInLine() == 0 }? '\n' -> popMode, type(NOVEL) ;

修改后解析器语法BlckVer2Parser.g4

parser grammar BlckVer2Parser ;

options {
  tokenVocab = BlckVer2Lexer ;
}

file : blk01 blk02 blk03 blk04+ blk05 EOF ;

blk01 : blk01Who blk01What ;
blk01Who : ARROW BLK01 ;
blk01What : ID assign ;

blk02 : blk02Who blk02What ;
blk02Who : ARROW BLK02 ;
blk02What : ID assign  assign* ;

blk03 : blk03Who blk03What+ ;
blk03Who : ARROW BLK03 ;
blk03What : ID assign assign* ;

blk04 : blk04Who blk04What ;
blk04Who : ARROW BLK04 ;
blk04What : NOVEL ;

blk05 : blk05Who blk05What+ ;
blk05Who : ARROW BLK05 ;
blk05What : ID assign assign* ;

assign : param (CHRCOLON|CHREQUAL) value ;
param : KEYPARPAR|KEYPARPRO1|KEYPARPRO2|KEYPARSIZ|KEYPARWGT|KEYPARPAG|KEYPARCNT|KEYPARCUR|KEYPARVAL ;
value : STRING|NUM|var ;
var : CHRAMP NAMVAR ;

修改后测试输入文件

->BLOCK01
START param=&wert

->BLOCK02
SELF property1="abc" property2="def"

->BLOCK03
ITEM1 property1:"xyz" property2:"set"
ITEM2 property1:"xyz" property2:"set"
ITEM3 property1:"xyz" property2:"set"

->BLOCK04
GOOD01 size:"2x3" weight:"23"
DOCUMENT01 pages:37
ORDER01 count:37

->BLOCK04
GOOD02 size:"5x6" weight:"32"
AMOUNT02 currency:"US" value:2033

->BLOCK04
ORDER03 count:44
DOCUMENT03 pages:24
GOOD03 size:"2x4" weight:"87"

->BLOCK05
GOOD0501 size:"3x7" weight:"34"
AMOUNT0501 currency:"EU" value:2025

效果说明

修改后可成功捕获BLOCK04的所有数据,例如第一个BLOCK04捕获到的内容为:

\nGOOD01 size:"2x3" weight:"23"\nDOCUMENT01 pages:37\nORDER01 count:37\n\n

目前需要预先将Windows换行符(\r\n)转换为Unix换行符(\n),后续可进一步适配\r\n格式。


内容的提问来源于stack exchange,提问作者Michael Rachow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 04:53:13