antlr4 - 克服词法歧义
问题描述
2020 年 10 月 25 日更新
我有一个面向记录的文件格式,其中('\r'? '\n' | '\r')
[ie NEWLINE] 可以是一系列字符的终止,或者单独作为两个记录之间的分隔符。每条记录中也有自由文本。
我遇到的两个问题是:
- 如果我在 TEXT 的定义中包含数字和标点符号,则
timestamp
停止识别, - 我想处理将两条记录与行终止换行不同的换行符。
我想解析这个简单的文件格式:
1 00:00:01,123 --> 00:00:10,000 第一个标题在这里 第二个标题在这里 2 00:00:10,001 --> 00:00:20,200 第三个字幕缺少第四个字幕
我的语法是这样的:
语法 str; str_file:记录+; 记录:frameLine 时间戳标题标题?新队 ; frameLine: FRAME_ID NEWLINE ; 时间戳:TIMECODE ARROW TIMECODE NEWLINE ; 标题:文字换行; 新行: ('\r'? '\n' | '\r') ; FRAME_ID: [0-9]+ ; 箭头:'-->'; 文本:('A'..'Z' | 'a'..'z' | ' ')+ ; 时间码:[0-9][0-9] ':' [0-9][0-9] ':' [0-9][0-9] ',' [0-9][0-9 ][0-9];
重构后更新
Bart 下面的答案肯定比我在下面的重构更可靠,这似乎也有效,但可能无法解析一些输入:
语法字幕; 字幕:记录+ EOF; 记录:frameLine 时间戳标题标题?新队 ; 框架线 FRAME_ID NEWLINE ; 时间戳:TIMECODE ARROW TIMECODE NEWLINE; 标题:文字换行; 新行: ('\r'? '\n' | '\r') ; FRAME_ID: [0-9]+ ; 箭头:'-->'; 时间码:[0-9][0-9] ':' [0-9][0-9] ':' [0-9][0-9] ',' [0-9][0-9 ][0-9]; 文本:(字 | 数字 | ' ' | PUNC)+; 字:[\u0041-\u007a\u00c0-\u00ff]+; 数字:('0'..'9')+; PUNC: '/' | '*' | ':' | ', ';
解决方案
问题在于某些字符在特定上下文中具有不同的含义:数字可以是帧 ID、时间戳的一部分或文本的一部分。从理论上讲,时间戳之类的00:00:10,001
甚至可以是一行文本的一部分。ANTLR 的词法分析器不能很好地处理这种上下文敏感性。
您可以做的是利用词法分析器模式。假设输入总是以帧 ID 开始,那么当词法分析器“看到”帧 ID 之后的换行符时,它就会进入时间模式。在这种时间模式下,您知道您将匹配用箭头分隔的时间戳,并且当您在该模式下“看到”新行时,您将进入文本模式。只要您“看到” 2 个连续的换行符,此文本模式就会结束。
快速演示:
文件:SrtLexer.g4
lexer grammar SrtLexer;
FRAME_ID
: [0-9]+
;
NEW_LINE
: NL -> skip, mode(TIME_MODE)
;
fragment NL : '\r'? '\n' | '\r';
fragment S : [ \t];
fragment D : [0-9];
mode TIME_MODE;
TIME_STAMP
: D D ':' D D ':' D D ',' D D D
;
ARROW
: '-->'
;
TIME_MODE_SPACE
: S -> skip
;
TIME_MODE_NEW_LINE
: NL -> skip, mode(TEXT_MODE)
;
mode TEXT_MODE;
TEXT_LINE
: ~[\r\n]+
;
TEXT_MODE_NEW_FRAME
: NL NL -> skip, mode(DEFAULT_MODE)
;
TEXT_MODE_NEW_LINE
: NL -> skip
;
文件:SrtParser.g4
parser grammar SrtParser;
options {
tokenVocab=SrtLexer;
}
parse
: frame+ EOF
;
frame
: FRAME_ID time text
;
time
: TIME_STAMP ARROW TIME_STAMP
;
text
: TEXT_LINE+
;
如果您现在解析示例输入,您将得到以下解析树:
请注意,这样输入如下:
1
00:00:01,123 --> 00:00:10,000
And then he typed 00:00:01,123 --> 00:00:10,000
也将被正确解析。
推荐阅读
- elasticsearch - Elasticsearch:获取处理器字段/类型?
- python - 试图将包含 str 'meta-analysis' 的文件(.txt 格式)从一个文件夹移动到另一个-python
- square-connect - 开始使用 square 和 php
- php - wordpress 循环不显示数据
- dart - 崩溃 ListView.builder
- c# - 使用 oidc 的 SPA、WEBAPI 和 Identity Server 4 的自定义声明?
- java - 升级到 1.1.0 后出现 kafka 错误:“状态存储...可能已迁移到另一个实例”
- wordpress - 更改为 ssl 后,wordpress 文件夹不再工作
- angular - 表达方式变了
- android - 使用协调器布局创建活动时出错