2013-06-22 16 views
2

我想使用PetitParserDart來解析dart字符串中的嵌入表達式。如何使用PetitParser匹配飛鏢字符串中的表達式?

準備一些對象:

class User { 
    String name; 
} 
var user1 = new User()..name="Mike"; 
var user2 = new User()..name="Jeff"; 
var user3 = new User()..name="John}}}"; 
var users = [user1, user2, user3]; 

長字符串:

var s = """ 
Hello, this is an embed dart expression below: 
    ${ 
    users.where((u)=>u.name!='Jeff}}}}}}}}') 
      .where((u) { return u.name!='{{{John'}) 
      .map((u)=>u.name).toList() 
    } 
It's very complex. 
""" 

你可以看到有字符串內使用${},其內容是很複雜的。

我嘗試使用這種petitparser代碼:

def("expr_in_string", string('${').ref('expr').char('}')); 
def("expr", ????); 

但我不知道如何定義expr規則。它可能包含{},所以我不能簡單地使用anyIn('{}').neg()

現在我該怎麼辦?我覺得這將是一個非常複雜的規則。

回答

1

我不認爲你可以正確解析所有可能的字符串,而沒有或多或少的完整的飛鏢表達語法。你可以寫一個近似值(就像你在答案中做的那樣),或者嘗試使用示例中附帶的Dart語法的表達式生成。無論哪種情況,結果語法都很複雜,因爲你試圖匹配的東西很複雜。

+0

謝謝你,盧卡斯。你能給我一個例子,說明我的解決方案無法正確處理嗎? – Freewind

+0

我認爲包含註釋的表達式處理不正確。 –

0

在src/dart/grammar.dart中有一個針對Dart的語法,它似乎可以解析它。

+0

我看過那個演示,但它太複雜了。 – Freewind

+0

取決於你想要完成什麼,你可能想看看analyzer_experimental作爲替代。 –

0

我找到了一個解決方案:確定${}內的字符串,首先匹配它們。然後匹配所有{}

代碼:

// whole `${...}` 
def("expr", string(r"$") & ref("block_brace")); 
// strings 
def("dart_str_single", char("'") & (string(r"\'") | char("'").neg()).star() & char("'")); 
def("dart_str_double", char('"') & (string(r'\"') | char('"').neg()).star() & char('"')); 
def("dart_str_triple_single", string("'''") & string("'''").neg().star() & string("'''")); 
def("dart_str_triple_double", string('"""') & string('"""').neg().star() & string('"""')); 
// (...) 
def("block_parenthesis", char('(') & (
    ref("dart_str_triple_single") 
    | ref("dart_str_triple_double") 
    | ref("dart_str_single") 
    | ref("dart_str_double") 
    | ref("block_parenthesis") 
    | ref("block_brace") 
    | char(')').neg() 
).star() & char(')')); 
// {...} 
def("block_brace", char('{') & (
    ref("dart_str_triple_single") 
    | ref("dart_str_triple_double") 
    | ref("dart_str_single") 
    | ref("dart_str_double") 
    | ref("block_parenthesis") 
    | ref("block_brace") 
    | char('}').neg() 
).star() & char('}')); 

測試代碼:

var x4 = grammar["expr"]; 
    var yyy4 = x4.parse(r"""${ 
    users.where((u) => u.name != 'Jeff}}}}}}}}') 
    .where((u) { 
    return u.name != '{{{John'; 
    }) 
    .map((u) => u.name).toList() 
    }"""); 
    print(yyy4.value); 

它打印:

[$, [{, [ 
, , , , , , , u, s, e, r, s, ., w, h, e, r, e, 
[(, [[(, [u],)], , =, >, , u, ., n, a, m, e, , !, =, , 
[', [J, e, f, f, }, }, }, }, }, }, }, }], ']],)], 
, , , , , , , ., w, h, e, r, e, [(, [[(, [u],)], , [{, 
[, , , , , , , , , r, e, t, u, r, n, , u, ., n, a, m, e, , !, =, , 
[', [{, {, {, J, o, h, n], '], ;, , , , , , , ], }]],)], 
, , , , , , , ., m, a, p, [(, [[(, [u],)], , =, >, , u, ., n, a, m, e],)], 
., t, o, L, i, s, t, [(, [],)], 
, , , , , , ], }]] 

我認爲這是正確的,但我仍然在尋找一個簡單的解決方案。


更新:

它不能處理這種複雜的代碼:

"""${ 
    users.where((u) => u.name != 'Jeff}}}}}}}}') 
    .where((u) { 
    return u.name != '{{{John${ 
    users.where((u) => u.name != 'Jeff}}}}}}}}') 
    .where((u) { 
    return u.name != '{{{John'; 
    }) 
    .map((u) => u.name).toList() 
    }'; 
    }) 
    .map((u) => u.name).toList() 
    }""" 

也就是說${}一個字符串,它內部的${}內。除此之外還有其他情況嗎?