使用antlr4解析iOS / macOS可本地化的字符串文件

时间:2018-09-24 22:18:20

标签: xcode antlr antlr4

我正在尝试解析macOS / iOS的本地化“字符串”文件。

此文件的格式基于键/值对,带有可选注释。下面是一个示例:

/* This is a comment */
// This is also a comment

"key1" = "value1";

"key2" = "value2";

,依此类推。 注意在“”中可以是任何类型的文本。

EDIT (原始错误neus语法已删除)

我试图编写这种简单的语法,但不幸的是它不起作用。

由于引号中的内容可能非常棘手,更不用说注释了,我觉得通常的正则表达式没有真正的力量。

根据@GRosenberg的评论,

EDIT 我创建了一个新的语法。现在我有一个问题,我不能将“符号”作为Char包含在内,否则解析会中断。

grammar LProj;

Esc         : '\\';
Spaces       : [ \t\r\n\f]+;
BlockComment   : '/*'  .*? ('*/' | EOF) ;
LineComment    : '//' ~[\r\n]* ( '\r'? '\n' [ \t]* '//' ~[\r\n]* )*  ;

MLN_COMMENT: BlockComment -> channel(HIDDEN) ;
SLN_COMMENT: LineComment  -> channel(HIDDEN) ;

doc : expression*;

expression
    :   BlockComment
    |   LineComment
    |   Spaces
    |   entry
    ;

entry : '"' key=VALUE '"' Spaces? '=' Spaces? '"' value=VALUE '"' Spaces? ';' ;


VALUE : ( EscSeq | Val )+ ;
fragment Val : Char ( EscSeq | Char )* ;

fragment Symbol
    :   '*'
    |   '/'
    |   ';'
    |   '='
    ;

fragment Char
    :   Spaces
    |   '!'         // skip "
    |   '#'..')'    // skip *
    |   '+'..'.'    // skip /
    |   '0'..':'    // skip ;
    |   '<'         // skip =
    |   '>'..'['    // skip \
    |   ']'..'~'
    |   '\u00B7'..'\ufffd'
    ;   // ignores | ['\u10000-'\uEFFFF] ;

fragment UnicodeEsc
    :   'u' (Hex (Hex (Hex Hex?)?)?)?
    ;

fragment Hex    : [0-9a-fA-F]   ;

fragment EscSeq
    :   Esc
        ( [btnfr"\\]    // standard escaped character set
        | UnicodeEsc    // standard Unicode escape sequence
        | .             // Invalid escape character
        | EOF           // Incomplete at EOF
        )
    ;

1 个答案:

答案 0 :(得分:0)

Antlr grammar repository提供了有关如何实现既定目标的良好示例。只需定义ID终端以允许包含转义序列即可。

因此(省略了明显的细节),

id    : QUOTE key=ID EQ val=ID QUOTE ;

DOC_COMMENT: DocComment   -> channel(HIDDEN) ;
MLN_COMMENT: BlockComment -> channel(HIDDEN) ;
SLN_COMMENT: LineComment  -> channel(HIDDEN) ;

NAME  : NameStartChar  NameChar* ;
VALUE : ( EsqSeq | Val )+ ;

fragment Val : NameStartChar ( EsqSeq | NameChar )* ;

fragment Hws            : [ \t]     ;
fragment Vws            : [\r\n\f]  ;

fragment DocComment     : '/**' .*? ('*/' | EOF) ;
fragment BlockComment   : '/*'  .*? ('*/' | EOF) ;
fragment LineComment    : '//' ~[\r\n]* ( '\r'? '\n' Hws* '//' ~[\r\n]* )*  ;

// escaped short-cut character or Unicode literal
fragment EscSeq
    :   Esc
        ( [btnfr"\\]    // standard escaped character set
        | UnicodeEsc    // standard Unicode escape sequence
        | .             // Invalid escape character
        | EOF           // Incomplete at EOF
        )
    ;

fragment Esc    : '\\'  ;
fragment UnicodeEsc
    :   'u' (Hex (Hex (Hex Hex?)?)?)?
    ;

// A valid hex digit
fragment Hex    : [0-9a-fA-F]   ;

fragment NameChar
    :   NameStartChar
    |   '0'..'9'
    |   '_'
    |   '\u00B7'
    |   '\u0300'..'\u036F'
    |   '\u203F'..'\u2040'
    ;

fragment NameStartChar
    :   'A'..'Z'
    |   'a'..'z'
    |   '\u00C0'..'\u00D6'
    |   '\u00D8'..'\u00F6'
    |   '\u00F8'..'\u02FF'
    |   '\u0370'..'\u037D'
    |   '\u037F'..'\u1FFF'
    |   '\u200C'..'\u200D'
    |   '\u2070'..'\u218F'
    |   '\u2C00'..'\u2FEF'
    |   '\u3001'..'\uD7FF'
    |   '\uF900'..'\uFDCF'
    |   '\uFDF0'..'\uFFFD'
    ;   // ignores | ['\u10000-'\uEFFFF] ;