2012-02-15 2 views
5

iOS 응용 프로그램의 경우 대체 할 UNIX 스타일 변수가 포함될 수있는 HTML 파일을 구문 분석하려고합니다. 이 감지 변수 통과 HTML에 대한 하나, 또 다른 : 나는 나에게이 콜백을 제공하는 간단한 ParseKit 문법을 만들려고 해요대체 변수가있는 HTML의 간단한 ParseKit 문법

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

: 같은 예를 들어, HTML은 보일 수 있습니다. 난 아직도 이유를 모른다 (I 원래 openChar Word closeChar로 선언했다 variable을 위해, 그러나 그것은 작동하지 않았다 :이와 함께 적어도 두 가지 문제에 직면하고있어

@start  = Empty | content*; 

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

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

:이를 위해, 나는 다음과 같은 문법을 만들어). 두 번째 문제는 (더 중요한) 구문 분석기가 <img src"${image}" /> (즉, 인용 된 문자열 안에있는 변수)을 찾으면 중지한다는 것입니다.

내 질문은 :

  1. 어떻게 예상대로 작동하도록 문법을 수정할 수 있습니다?
  2. 토크 나이저를 사용하는 것이 더 좋습니까? 그렇다면 어떻게 구성해야합니까?

답변

4

개발자는 여기 ParseKit. 귀하의 질문에 모두 답변 드리겠습니다 :

1) 올바른 접근 방법을 취하고 있지만 이것은 까다로운 경우입니다. 몇 가지 작은 문제가 있으며 문법을 약간 변경해야합니다.

내가 나를 위해 노력하고 문법 개발 한

:

// 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; 

이 그런 다음 어셈블러이 두 콜백을 구현을 :

- (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; 
} 

그리고 클라이언트/드라이버 코드는 같을 것이다 이 :

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); 

이 인쇄됩니다 :

result: <img src="" /> 

2) 예, 나는 확실히이 비교적 간단한 경우 직접 토크 나이를 사용하는 것이 훨씬 더 좋을 것이다 생각합니다. 성능은 엄청나게 좋아질 것입니다. 다음은 Tokenizer로 작업에 접근하는 방법입니다.

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

감사합니다. Todd! 더 빠르고 덜 복잡한 구현으로 보이기 때문에 토큰 화 방법을 택할 것입니다. 그래도 어느 시점에서는 문법을 사용하기를 기대합니다. – pgb