我正在解析PDF内容流。字符串由括号定界,但可以包含嵌套的未转义括号。从PDF参考:
文字字符串应写成用括号括起来的任意数量的字符。除不平衡括号(左括号(28h)和右括号(29h))和反斜杠(RESOLE SOLIDUS(5Ch))外,任何字符都可以出现在字符串中,这些字符应按本小节中的描述进行特殊处理。字符串中的括号对之间不需要特殊处理。
示例1:
The following are valid literal strings:
(This is a string)
(Strings may contain newlines
and such.)
(Strings may contain balanced parentheses ( ) and special characters (*!&}^% and so on).)
似乎可以将lexer模式推到堆栈上来解决这个问题。这是我的词法分析器和解析器的精简版本。
lexer grammar PdfStringLexer;
Tj: 'Tj' ;
TJ: 'TJ' ;
NULL: 'null' ;
BOOLEAN: ('true'|'false') ;
LBRACKET: '[' ;
RBRACKET: ']' ;
LDOUBLEANGLE: '<<' ;
RDOUBLEANGLE: '>>' ;
NUMBER: ('+' | '-')? (INT | FLOAT) ;
NAME: '/' ID ;
// A sequence of literal characters enclosed in parentheses.
OPEN_PAREN: '(' -> more, pushMode(STR) ;
// Hexadecimal data enclosed in angle brackets
HEX_STRING: '<' [0-9A-Za-z]+ '>' ;
fragment INT: DIGIT+ ; // match 1 or more digits
fragment FLOAT: DIGIT+ '.' DIGIT* // match 1. 39. 3.14159 etc...
| '.' DIGIT+ // match .1 .14159
;
fragment DIGIT: [0-9] ; // match single digit
// Accept all characters except whitespace and defined delimiters ()<>[]{}/%
ID: ~[ \t\r\n\u000C\u0000()<>[\]{}/%]+ ;
WS: [ \t\r\n\u000C\u0000]+ -> skip ; // PDF defines six whitespace characters
mode STR;
LITERAL_STRING : ')' -> popMode ;
STRING_OPEN_PAREN: '(' -> more, pushMode(STR) ;
TEXT : . -> more ;
parser grammar PdfStringParser;
options { tokenVocab=PdfStringLexer; }
array: LBRACKET object* RBRACKET ;
dictionary: LDOUBLEANGLE (NAME object)* RDOUBLEANGLE ;
string: (LITERAL_STRING | HEX_STRING) ;
object
: NULL
| array
| dictionary
| BOOLEAN
| NUMBER
| string
| NAME
;
content : stat* ;
stat
: tj
;
tj: ((string Tj) | (array TJ)) ; // Show text
当我处理此文件时:
(Oliver’s Army) Tj
((What’s So Funny ’Bout) Peace, Love, and Understanding) Tj
我收到此错误并解析树:
line 2:24 extraneous input ' Peace, Love, and Understanding)' expecting 'Tj'
因此,pushMode
可能不会将重复模式推入堆栈。如果没有,处理嵌套括号的方式将是什么?
我省略了有关字符串中转义序列的说明:
在文字字符串中,REVERSE SOLIDUS用作转义字符。如表3所示,REVERSE SOLIDUS之后的字符确定其精确解释。如果REVERSE SOLIDUS之后的字符不是表3中所示的字符之一,则应忽略REVERSE SOLIDUS。
表3列出了\n
,\r
,\t
,\b
退格键(08h),\f
换页(FF),\(
, \)
,\\
和\ddd
字符代码 ddd (八进制)
出现在文字字符串中且没有前面的RESOLE SOLIDUS的行尾标记应被视为字节值(0Ah),无论该行尾标记是否为CARRIAGE RETURN(0Dh), LINE FEED(0Ah),或两者兼有。
示例2:
(These \
two strings \
are the same.)
(These two strings are the same.)
示例3:
(This string has an end-of-line at the end of it.
)
(So does this one.\n)
我应该使用以下STRING定义:
STRING
: '(' ( ~[()]+ | STRING )* ')'
;
在我的代码中没有模式并处理转义序列,还是为字符串创建词法分析器模式并在语法中处理转义序列?
答案 0 :(得分:1)
您可以使用词法模式执行此操作,但是在这种情况下,并不需要它。您可以像这样简单地定义词法分析器规则:
STRING
: '(' ( ~[()]+ | STRING )* ')'
;
使用转义序列,您可以尝试:
STRING
: '(' ( ~[()\\]+ | ESCAPE_SEQUENCE | STRING )* ')'
;
fragment ESCAPE_SEQUENCE
: '\\' ( [nrtbf()\\] | [0-7] [0-7] [0-7] )
;