2016-08-30 21 views
4

我想解析純文本註釋並在其中查找特定標籤。該類型的標籤我在尋找的樣子:從任意純文本中抽取特定標籤

<name#1234> 

其中 「名」 是[A-Z]字符串(從一個固定的列表)和 「1234」 代表[0-9] +號。這些標籤可以出現在零次或多次字符串中,並被任意其他文本包圍。例如,下列字符串都是有效的:

"Hello <foo#56> world!" 
"<bar#1>!" 
"1 &lt; 2" 
"+<baz#99>+<squid#0> and also<baz#99>.\n\nBy the way, maybe <foo#9876>" 

以下字符串都是無效的:因爲「notinfixedlist」是不受支持的命名標識

"1 < 2" 
"<foo>" 
"<bar#>" 
"Hello <notinfixedlist#1234>" 

最後一個是無效。

我可以很容易地解析此使用簡單的regex,例如(我省略爲了簡單起見命名組):

<[a-z]+#\d+> 

或直接指定一個固定的列表:

<(foo|bar|baz|squid)#\d+> 

但我'd喜歡使用antlr的原因如下:

  • 我想要任何與該格式不匹配的東西導致解析錯誤,所以如果文本包含「<」或「>」但與模式不匹配,則失敗。這些字符必須轉義爲「& lt;」和「& gt」;如果它不是標籤的話。
  • 爲了支持其他類型的模式(例如:「{foo + 666}」或「[[1234]]」,我可能會擴展它,並希望避免正則表達式的爆炸。文件我可以擴展將是巨大的。
  • 我喜歡antlr4實現訪問者模式,當遇到,而不必砍一起變化的正則表達式的特定類型的標籤我的代碼被調用的事實。

我如何使用antlr4實現這樣的語法?我見過的大多數例子都是針對整個文本遵循精確規則的語言,而我只希望語法適用於任意文本中的匹配模式。

我來到了這一點,我相信這是正確的:

grammar Tags; 

parse 
    : (tag | text)* 
    ; 

tag 
    : '<' fixedlist '#' ID '>' 
    ; 

fixedlist 
    : 'foo' 
    | 'bar' 
    | 'baz' 
    | 'squid'; 

text 
    : ~('<' | '>')+ 
    ; 

ID 
    : [0-9]+ 
    ; 

這是正確的嗎?

+1

很好地提出了問題,但不適合SO,因爲它主要是基於意見的。 – itsme86

+1

好點。我將修改這個問題,具體問一下如何在antlr中實現。 –

+1

你可能只需要兩個規則就可以讓你的詞法分析器:一個標籤和一個CHAR,然後語法就是一個'(TAG | CHAR)*'。 – Jacob

回答

2

一般來說,所發現的問題通常被描述爲孤島語法問題 - 其中單數文檔的部分由兩個或更多個不同的,通常相互模糊的規範描述。

ANTLR 4通過使用mode s直接支持孤島語法。請注意,模式僅適用於拆分詞法分析器/分析器語法。

解析器

parser grammar TagsParser ; 

options { 
    tokenVocab = TagsLexer ; 
} 

parse : (tag | text)* EOF ; 
tag  : LANGLE fixedlist GRIDLET ID RANGLE ; 
text : . ; 
fixedlist 
    : FOO 
    | BAR 
    | BAZ 
    | SQUID 
    ; 

詞法分析器

lexer grammar TagsLexer ; 

LANGLE : '<' -> pushMode(tag) ; 
TEXT : . ; 

mode tag ; 
    RANGLE : '>' -> popMode ; 

    FOO  : 'foo' ; 
    BAR  : 'bar' ; 
    BAZ  : 'baz' ; 
    SQUID : 'squid' ; 
    GRIDLET : '#' ; 
    ID  : [0-9]+ ; 

    NONTAG : . -> popMode ; 

text規則解析器將匹配以前沒有它上面的語法規則消耗的所有令牌。這將包括所有TEXT標記以及恰好與標記模式規則匹配但不是標籤有效部分的任何文本。

+0

「TEXT」定義的目的是什麼?它似乎沒有在詞法分析器語法中使用,或者在我缺少的「文本」和「文本」之間存在隱含的關係? –

+1

文檔開始後的任何內容,或「NONTAG」,以及「LANGLE」之前的內容都是「TEXT」。 – GRosenberg

+0

是的,我明白從解析器的'(tag | text)*'行和'text'匹配任何不是標籤的字符。我只是不明白詞法分析器中的「TEXT」行。換句話說,解析器文本之間有什麼區別:。 ;'和詞法分析器'TEXT:。 ;'線,什麼時候是'TEXT'實際使用(它的定義,但似乎沒有用於我)? –