2011-01-08 11 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を使用しています)を使用して、 "チャンク"私はどのように私は/正規表現を使用して外に全体の変数名を得るかもしれないか分からないのですか?

このクラスはかなり複雑になりつつあります。そのため、私はさらに進める前に正しいアプローチを取っていますか?

私の2の懸念は、以下のとおりです。

  1. カウンタを現在の位置からテキストのチャンクを引き出し、そして進めるための良い方法は何ですか?たとえば、変数名を抽出すると、次のテキストが実際には変数名になるはずです。
  2. すぐにテンプレートを何度も何度もレンダリングできるように、ノード(この場合はテキストノードと変数ノードのみ)を保存する方法はありますか?

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

    また、私はテキストを解析するときに例外をスロー避けるだろう:についてどう

+0

テンプレートでレンダリングしようとするのは、テキストだけですか? RegExesは分岐構造には適していません。 – pbalaga

+0

@rook:はい、 "text"とは "文字列"を意味しますが、将来はJSONやXMLなどのHTMLになります。明確にするために、*出力*は入力ではなくHTMLです。 – mpen

答えて

2

。ユーザーの文字列には事実上何でも含めることができるので、予期せぬデータを可能な限りインテリジェントに処理してください。

+0

これは単純な変数置換ではありません。ループのようなものを追加するつもりですが、正規表現は機能しません。私は例外を投げることはあまりにも悪いとは思わない。彼らが間違ったテンプレートを書いた場合、彼らはそれについて知る必要があります。どちらかというと、静かに何も吐き出されず、なぜ正しくレンダリングされないのか、彼らは頭を傷つける。 – mpen

+1

申し訳ありませんが、あなたがしようとしていることを完全に理解していない場合。私はちょうどこれのようなもののトンをやった。単純なパーサーヘルパークラスが必要な場合は、私のテキストパースヘルパークラス(http://www.blackbeltcoder.com/Articles/strings/a-text-parsing-helper-class)をチェックしてください。 –

+0

私はこれを解析するために使うつもりです。http://programmers.stackexchange.com/questions/34761このクラスはちょうど始まりです。あなたは自分の記事で、文字ごとにスキャンする必要があると言った;) – mpen

1

あなたのノードにはある種の連想型コンテナを使用したいと思うでしょうが、Listの代わりにDictionary<string, Node>をお勧めしますか?また、私は現在、これらのノードを設定する方法がありません。そして、あなたが進んでいる間にノードをクラスにすることもできます。

charでcharを解析してから正規表現を使うのであれば、それはおそらく理想的ではないかもしれませんが、tokenizer/lexerを書くことはどちらも簡単な作業ではありません。あなたが必要なときにそれを修正!

+0

ええ、私はANTLRでおしゃべりしてきましたが、あまり好きではありません。とにかく私が望んでいるもののために過度のことかもしれない。 'Dictionary 'はどのように役立つでしょうか?私はまだ 'O(n)'となる変数ノードを引き出す必要があり、辞書は順序付けされていないのですか?テンプレートを解析した後、読み込みとレンダリングだけでノードを再設定する必要はありません。 – mpen

+0

辞書は挿入されていません。少なくとも、挿入順ではありません。辞書は検索のためにキー値を保存するが、順番に処理するリストは保存しないのが良い場所です。 –

0

文字列のすべての文字をループするのではなく、文字列全体に対してRegExを実行し、一致のコレクションを返すだけです。

+0

検索と置換だけではできません。変数だけでなく、もっと多くの要素があります...分岐するので、私は線形に処理する必要があります。 – mpen

1

テンプレートを複数回使用する場合は、テンプレートを2ステップで解析することをお勧めします。まず、テンプレートをリテラルテキストとフィールドオブジェクトに分割してリストに格納し、次にレンダリングする必要がありますリストの上をループし、リテラルテキストを直接出力し、各フィールドの辞書を呼び出します。

私たちは、regexから来る私たち自身のtemlpateエンジンと同様のことを、あらかじめ解析されたリストに置き換え、約20倍のパフォーマンスを向上させました。

現在のコードは、元の文字列を分割するのに最適です。

例:

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の場合、ハンドコーディングされたスプリッタは十分です。私たちが使用した最初のものは、20分で私の同僚によって書かれました;)あなたのコードにかなり似ていました; –

関連する問題