2011-01-08 19 views
1

방금 ​​간단한 클래스를 썼습니다. 그것이 않는 모든 @name, 당신은 @adjective 오늘 볼 안녕하세요이 간단한 템플릿 렌더링 클래스를 향상시키는 방법은 무엇입니까?

같은 입력 문자열을 사용합니다!

그리고 @variables은 사전의 값으로 바뀝니다. 예를 들어, new Dictionary<string,object>{{"name","Ralph"},{"adjective","stunning"}}를 전달하는 줄 것입니다 :

안녕하세요 랄프는, 오늘 멋진 봐!

class Template 
{ 
    List<object> nodes = new List<object>(); 

    public Template(string content) 
    { 
     for (int i = 0; i < content.Length; ++i) 
     { 
      char ch = content[i]; 

      if (ch == '@') 
      { 
       var match = Regex.Match(content.Substring(i + 1), @"\w+"); 
       if (match.Success) 
       { 
        nodes.Add(new Variable(match.Value)); 
        i += match.Value.Length; 
       } 
       else 
       { 
        throw new Exception(string.Format("Expected variable name after @ symbol at character {0}", i)); 
       } 
      } 
      else 
      { 
       nodes.Add(ch.ToString()); 
      } 
     } 
    } 

    public string Render(Dictionary<string,object> dict) 
    { 
     var sb = new StringBuilder(); 
     foreach (var item in nodes) 
     { 
      if (item is Variable) 
      { 
       sb.Append(dict[((Variable)item).Name]); 
      } 
      else 
      { 
       sb.Append(item); 
      } 
     } 
     return sb.ToString(); 
    } 

    class Variable 
    { 
     public readonly string Name; 
     public Variable(string name) 
     { 
      Name = name; 
     } 
    } 
} 

이 이러한 문제에 좋은 방법입니다 : 여기

클래스입니까? 가능한 한 많은 처리를 생성자에서 수행하여 재구성하지 않고 효율적으로 템플릿을 반복해서 렌더링 할 수 있습니다.

지금은 변수 노드를 찾기 위해 전체 노드 목록을 반복하고 있습니다. 대신 대체 할 수 있습니다. 그 노드에 "건너 뛸"수있는 방법이 있을까요? 그게 도움이 되겠습니까?

또한 문자로 문자를 구문 분석하고 있지만 그 다음 정규식을 사용합니다 (다음 문자에서 시작하고 싶습니다. 그래서 .Substring을 사용하여 나머지 문자열을 가져옵니다). "청크 "텍스트의. 정규식을 사용하여 전체 변수 이름을 어떻게 얻을 수 있을지 모르겠습니다.

이 클래스는 훨씬 더 복잡해 지므로 앞으로 더 가야하기 전에 올바른 접근 방식을 갖고 싶습니다.

내이 문제는 다음과 같습니다

  1. 카운터를 현재 위치에서 텍스트의 체크를 꺼내하고 발전 할 수있는 좋은 방법은 무엇입니까? 예를 들어, 일단 텍스트의 다음 비트가 사실 변수 이름이어야한다고 결정하면 변수 이름을 추출합니다.
  2. 빨리 템플릿을 반복해서 렌더링 할 수있는 노드 (이 경우 텍스트 및 변수 노드 만)를 어떻게 저장해야합니까? 텍스트를 구문 분석 할 때 또한

    s = s.Replace("@name", name); 
    s = s.Replace("@Adjective", adjective); 
    

    , 나는 예외를 던지는 피할 것 :에 대해 무엇

+0

템플릿으로 렌더링하려는 텍스트가 텍스트입니까? RegExes는 분기 된 구조에는 적합하지 않습니다. – pbalaga

+0

@rook : 예, "text"는 "문자열"을 의미하지만 HTML이면 ... JSON 또는 XML입니다. 명확하게 말하면 * 출력 *은 입력이 아닌 HTML입니다. – mpen

답변

2

. 사용자 문자열에는 거의 모든 것이 포함될 수 있으므로 예기치 않은 데이터를 가능한 한 지능적으로 처리하고 시도하는 것이 좋습니다.

+0

단순한 변수 대체가되지 않습니다. 나는 루프와 같은 것을 추가 할 것이고, 정규 표현식은 작동하지 않을 것이다. 나는 예외를 던지기가 너무 나쁘다고 생각하지 않는다. 템플릿을 잘못 작성했다면 템플릿에 대해 알아야합니다. 그 중 하나, 또는 아무것도 조용히 침을 뱉어 머리가 왜 제대로 렌더링되지 않는지를 긁어냅니다. – mpen

+1

내가하려는 일을 완전히 이해하지 못해 죄송합니다. 나는 방금 이렇게 많은 것을했습니다. 간단한 구문 분석기 도우미 클래스가 필요한 경우 내 텍스트 구문 분석 도우미 클래스 (http://www.blackbeltcoder.com/Articles/strings/a-text-parsing-helper-class)를 확인하십시오. –

+0

이 코드를 사용하여 http://servermers.stackexchange.com/questions/34761을 파싱 할 예정입니다.이 클래스는 시작일뿐입니다. 당신은 당신의 기사에서 캐릭터별로 스캔 할 필요가 있다고 말했습니다.) – mpen

1

노드에 대해 일종의 연관 컨테이너를 사용하고 싶다면 List 대신 Dictionary<string, Node>을 권장할까요? 또한 현재 노드를 설정할 방법이 없습니다. 그리고 여러분은 노드를 클래스로 만들 수 있습니다.

char에 의해 char을 파싱 한 다음 정규식을 사용하는 경우에는 이상적이지는 않지만 tokenizer/lexer를 작성하는 것이 가장 간단한 작업이 아닙니다. 필요한 경우 수정하십시오!

+0

그래, 나는 ANTLR로 도박을 해왔다. 그러나 나는 아직 그것에 매달리지 않았다. 너무 좋아하지 않았다. 어쨌든 내가 원하는 것을 과용 할 수 있습니다. 'Dictionary '은 어떻게 도움이 될까요? 여전히 변수 노드를 꺼내야 할 것입니다. 변수 노드는 여전히'O (n)'이 될 것이고, 사전은 정렬되지 않았습니까? 템플리트가 구문 분석 된 후 노드를 다시 설정하지 않고 단지 읽고 렌더링 할 수 있습니다. – mpen

+0

사전은 삽입되지 않습니다. 적어도 삽입 순서는 아닙니다. 사전은 조회를 위해 keyvalue를 저장하지만 순서대로 처리 할 목록을 저장하지 않는 좋은 장소입니다. –

0

문자열의 모든 문자를 반복하는 대신 전체 문자열에 대해 RegEx를 실행하고 일치하는 항목을 반환해야합니다.

+0

찾기 및 바꾸기만으로는 안됩니다. 변수 들보 다 더 많은 요소가있을 것입니다 ...분기 할 것이므로 선형으로 처리해야합니다. – mpen

1

템플릿을 여러 번 사용하려는 경우 2 단계 템플릿을 구문 분석하는 것이 좋습니다. 먼저 템플릿을 리터럴 텍스트와 필드 개체로 분할하여 목록에 저장 한 다음 렌더링 할 때마다 그냥 목록을 반복하고 리터럴 텍스트를 직접 출력하고 각 필드의 사전을 호출합니다.

우리는 정규식에서 나온 자체 temlpate 엔진과 비슷한 구문을 사용하여 미리 구문 분석 된 목록을 대체하고 약 20 배의 성능 향상을 보였습니다. D.

현재 코드는 원래 문자열을 분할하는 데 적합합니다.

예 :

List<Node> nodes = var list = new List<node> {new node {Type=ntypes.literal,Value="Hello "}, new node{Type=ntypes.field,Value="Name"}}; 

Enum NodeType { 
    field, 
    literal 
} 
class Node { 
    public enum NodeType; 
    public string Value; 
} 

만 occationally 당신은 아직도 그것을 분할하지만 당신은 아주 쉽게 사용하지 않고 목록을 다시 만들 수 있도록 다음 eaxmple JSON에 대한의 배열을 저장하거나 직렬화 수를 사용할 경우 정규식.

또한 배열에 (type, value)가있는 요소가 있으면 시간이 지남에 따라 더 많은 지능을 추가 할 수 있습니다. 여러 개의 서로 다른 사전 또는 @@ substring (@field, 10)과 같은 간단한 함수가 파싱되어 실행됩니다.)

그러나 복잡한 상황에서는 실제 파서 솔루션을 사용하는 것이 복잡성이 증가함에 따라 단순한 솔루션은 모두 성능이 저하되고 성능이 저하됩니다.

마지막으로 Antlr 기반 파서를 사용했으며 현재 렌더링 단계의 표현 트리를보고 있습니다.

+0

글쎄, 그게 내가하려는 일이야. 이제는 좋은 접근 방법이 된 것을 기쁘게 생각합니다. 먼저 직접 파싱 해보려고합니다 ... 그러면 C# 파서 생성기를 시도해 볼 수도 있습니다 ... 지금 호출 된 것을 잊어 버리십시오. – mpen

+0

간단한 @fieldnames에서는 handcoded 스플리터가 충분합니다. 우리가 사용한 첫 번째 코드는 20 분 안에 제 동료가 작성했습니다.) 코드와 꽤 유사합니다;) –