2012-02-15 23 views
5

Đối với ứng dụng iOS, tôi muốn phân tích cú pháp tệp HTML có thể chứa biến kiểu UNIX để thay thế. Ví dụ, HTML có thể trông giống như:Ngữ pháp ParseKit đơn giản cho HTML với các biến thay thế

<html> 
    <head></head> 
    <body> 
    <h1>${title}</h1> 
    <p>${paragraph1}</p> 
    <img src="${image}" /> 
    </body> 
</html> 

Tôi đang cố gắng để tạo ra một ngữ pháp ParseKit đơn giản mà sẽ cung cấp cho tôi hai callbacks: Một cho HTML passthrough, và một cho các biến nó phát hiện. Cho rằng, tôi đã tạo ngữ pháp sau:

@start  = Empty | content*; 

content  = variable | passThrough; 
passThrough = /[^$]+/; 
variable  = '$' '{' Word closeChar; 

openChar  = '${'; 
closeChar  = '}'; 

Tôi đang phải đối mặt với ít nhất hai vấn đề với điều này: cho variable Ban đầu tôi đã tuyên bố nó như openChar Word closeChar, nhưng nó đã không làm việc (tôi vẫn không biết tại sao). Vấn đề thứ hai (và quan trọng hơn) là trình phân tích cú pháp dừng lại khi nó tìm thấy <img src"${image}" /> (tức là một biến bên trong một chuỗi được trích dẫn).

Câu hỏi của tôi là:

  1. Làm thế nào tôi có thể sửa đổi ngữ pháp để làm cho nó làm việc như mong đợi?
  2. Sử dụng trình mã thông báo có tốt hơn không? Nếu đúng như vậy, tôi nên cấu hình nó như thế nào?

Trả lời

4

Nhà phát triển của ParseKit tại đây. Tôi sẽ trả lời cả hai câu hỏi của bạn:

1) Bạn đang sử dụng đúng cách, nhưng đây là một trường hợp phức tạp. Có một số gotchas nhỏ, và ngữ pháp của bạn cần phải được thay đổi một chút.

tôi đã phát triển một ngữ pháp mà là làm việc cho tôi:

// Tokenizer Directives 
@symbolState = '"' "'"; // effectively tells the tokenizer to turn off QuoteState. 
         // Otherwise, variables enclosed in quotes would not be found (they'd be embedded in quoted strings). 
         // now single- & double-quotes will be recognized as individual symbols, not start- & end-markers for quoted strings 

@symbols = '${'; // declare '${' as a multi-char symbol 

@reportsWhitespaceTokens = YES; // tell the tokenizer to preserve/report whitespace 

// Grammar 
@start = content*; 
content = passthru | variable; 
passthru = /[^$].*/; 
variable = start name end; 
start = '${'; 
end = '}'; 
name = Word; 

Sau đó thực hiện hai callbacks này trong Assembler của bạn:

- (void)parser:(PKParser *)p didMatchName:(PKAssembly *)a { 
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a); 
    PKToken *tok = [a pop]; 

    NSString *name = tok.stringValue; 
    // do something with name 
} 

- (void)parser:(PKParser *)p didMatchPassthru:(PKAssembly *)a { 
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a); 
    PKToken *tok = [a pop]; 

    NSMutableString *s = a.target; 
    if (!s) { 
     s = [NSMutableString string]; 
    } 

    [s appendString:tok.stringValue]; 

    a.target = s; 
} 

Và sau đó khách hàng mã/lái xe của bạn sẽ trông giống như này:

NSString *g = // fetch grammar 
PKParser *p = [[PKParserFactory factory] parserFromGrammar:g assembler:self]; 
NSString *s = @"<img src=\"${image}\" />"; 
[p parse:s]; 
NSString *result = [p parse:s]; 
NSLog(@"result %@", result); 

Điều này sẽ được in:

result: <img src="" /> 

2) Vâng, tôi nghĩ rằng nó chắc chắn sẽ tốt hơn nhiều để sử dụng Tokenizer trực tiếp đối với trường hợp tương đối đơn giản này. Hiệu suất sẽ được ồ ạt tốt hơn. Dưới đây là cách bạn có thể tiếp cận công việc với Trình mã thông báo:

PKTokenizer *t = [PKTokenizer tokenizerWithString:s]; 
[t setTokenizerState:t.symbolState from:'"' to:'"']; 
[t setTokenizerState:t.symbolState from:'\'' to:'\'']; 
[t.symbolState add:@"${"]; 
t.whitespaceState.reportsWhitespaceTokens = YES; 

NSMutableString *result = [NSMutableString string]; 

PKToken *eof = [PKToken EOFToken]; 
PKToken *tok = nil; 
while (eof != (tok = [t nextToken])) { 
    if ([@"${" isEqualToString:tok.stringValue]) { 
     tok = [t nextToken]; 
     NSString *varName = tok.stringValue; 

     // do something with variable 
    } else if ([@"}" isEqualToString:tok.stringValue]) { 
     // do nothing 
    } else { 
     [result appendString:tok.stringValue]; 
    } 
} 
+1

Cảm ơn Todd! Tôi sẽ lấy cách tiếp cận tokenizer, vì nó có vẻ nhanh hơn và thực hiện phức tạp hơn nhiều. Tôi mong muốn sử dụng một ngữ pháp tại một số điểm, mặc dù. – pgb

Các vấn đề liên quan