日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SimpleTemplate模板引擎开发

發布時間:2025/5/22 编程问答 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SimpleTemplate模板引擎开发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

模板引擎相信大家是經常使用的,但是實現原理估計沒多少人知道(你要是說不就是replace嘛,那我也無話說了...)。


先來看看這個SimpleTemplate想實現的是什么功能吧:

  • 是個C#端的模板引擎
  • 模板中能放普通變量(i, j, index, username這種直接了當的變量名)
  • 模板中能放復合變量(user.FirstName, user.LastName這種有對象前綴的變量)
  • 最終客戶端代碼通過下面的方式進行調用:?

    static void Main(string[] args){string template = @" your name: @{name} your age: @{age} ";Dictionary<string, object> ctx = new Dictionary<string, object>();ctx["name"] = "McKay";ctx["age"] = "你猜";Console.WriteLine(STParser.GenerateStringView(template, ctx));Console.ReadKey();}

    ?

    大家看出來了,重點就在@{xxxx}上

    大家也先別噴我,說用正則、replace就搞定了,看后面先,小心噴了后悔。

    ?

    我選擇用antlr來做這個模板引擎,因為雖然現在看上去這個模板引擎很簡單,但是不代表以后不擴展啊,以后還要加入if/else/for這種通用編程語法的,所以為了擴展性,就用語法解析器了。

    知道yacc/flex的也可以去看看,只不過沒有C#插件,而antlr正好有這插件,就用了。

    ?

    下面我們先來寫文法規則:

    parse:expression*;expression: stringtext| simple_variable| complex_variable;

    ?

    parse

    規則代表開始規則,這個名稱可以自己起名,只要是小寫就行。

    內容只有一行,expression*,代表0個或者無限個expression規則

    expression

    看清,第一個是冒號“:”,后續的是或者號“|”,最后是封號";"

    代表expression可以是三種規則中的一種:stringtext、simple_variable、complex_variable,代表普通的字符串文本、簡單變量、復合變量規則

    ?

    先來看看普通文本字符串的定義

    stringtext: placeholderChar (placeholderChar)*| newlines;placeholderChar: CHAR| ':'| SPACE| NUMBER| DOT| '\''| '"'| '<'| '>'| '_'| '+'| '-'| '*'| '/';newlines:NEWLINE NEWLINE*;NEWLINE:'\r'? '\n'; NUMBER: '0'..'9'; CHAR: 'a'..'z'|'A'..'Z'; SPACE:' '; DOT:'.';

    ?

    stringtext

    二選一的規則

    第一行代表至少一個占位字符的字符串(后面用了*號,就代表字符數不限)?

    newlines,看后面的定義也是用了*號,代表一個回車,或者多個回車的規則匹配

    占位符,大家看placeholderChar規則,就知道允許的占位符是哪些字符了

    ?

    注意:大寫的規則其實不是規則,而是token

    ?

    再來看看簡單變量規則的定義

    simple_variable:V_START simple_variable_inner V_END;simple_variable_inner:identity;identity:(UNDERLINE|CHAR) (UNDERLINE|CHAR|NUMBER)*;V_START:'@{'; V_END:'}'; NUMBER: '0'..'9'; CHAR: 'a'..'z'|'A'..'Z'; UNDERLINE: '_';

    ?

    simple_variable

    定義了一個V_START的TOKEN為開頭,也定義了必須以V_END為結尾,字符分別是 ?@{和},呵呵,中間就是那個變量名了

    這個變量名其實就是identity規則的定義,是說第一個字符必須以下劃線或英文字母開頭,后續字符可有可無,有的話必須是下劃線、英文字母、數字

    ?

    再看看復合變量的規則

    complex_variable:V_START complex_variable_inner V_END; complex_variable_inner:identity DOT identity;identity:(UNDERLINE|CHAR) (UNDERLINE|CHAR|NUMBER)*;DOT:'.';

    ?

    說說這里的complex_variable_inner規則

    由于是要匹配obj.property格式,因此用了個點號DOT,obj和property的規則匹配其實就是identity的規則匹配?

    ?

    我們看看上面規則的效果,antlr解析樹:

    還是比較帥的

    下面的問題是,怎么運用到C#項目中了?

    ?

    怎么運用到C#項目中

    首先,新建一個項目,然后在NuGet中搜索"antlr" ,找到antlr4,然后安裝

    ?

    然后新建一個任意文件,新建后重命名為g4文件,比如SimpleTemplate.g4,接著還要設置下這個g4文件的生成方式,如下圖

    這樣,當我們生成時,antlr就會根據g4文件的規則定義生成對應的C#代碼了。

    ?

    然后再說說g4文件的內容是怎么拷貝過來(原先的解析樹是在eclipse中才能看的,所以原先的g4定義都在那邊做的)

    首先,上方的grammar xxxxx;這里的xxxxx必須要和文件名稱一致。

    其次,compileUnit后面的那個規則,必須存在,代表默認規則

    再其次,如果編譯時總是報錯(但是eclipse中是正常的),這時要修改下vs環境下的g4文件的編碼,如下:

    ?

    還得把eclipse中的g4文件內容拷貝到新的g4文件中,別忘了。

    ?

    接下來就要進入C#編碼層面了,呵呵,是不是有點不耐煩了,`(*∩_∩*)′

    ?

    掛鉤函數就那么一個,很簡單,基本就是拷貝:

    public static class STParser{public static string GenerateStringView(string template, Dictionary<string, object> variables){Antlr4.Runtime.AntlrInputStream input = new Antlr4.Runtime.AntlrInputStream(template);TemplateLexer lexer = new TemplateLexer(input);Antlr4.Runtime.UnbufferedTokenStream tokens = new Antlr4.Runtime.UnbufferedTokenStream(lexer);TemplateParser parser = new TemplateParser(tokens);var tree = parser.parse();SimpleTemplateVisitor visitor = new SimpleTemplateVisitor(variables);string result=visitor.Visit(tree);return result;}}

    ?

    template是傳進來的模板文本

    variables是傳進來的變量集合

    這段代碼中都是antlr引擎自動生成的類,除了SimpleTemplateVisitor是自定義的(不然咋替換字符串啊)

    來看看這個類吧,里面都是VisitXXXX規則的函數重載,需要的自定義邏輯都在里面改寫

    class SimpleTemplateVisitor:g4.TemplateBaseVisitor<string>{private Dictionary<string, object> ctx;public SimpleTemplateVisitor(Dictionary<string, object> ctx){this.ctx = ctx;}public override string VisitParse(g4.TemplateParser.ParseContext context){StringBuilder sb = new StringBuilder();foreach(var exp in context.expression())sb.Append(VisitExpression(exp));return sb.ToString();}public override string VisitNewlines(g4.TemplateParser.NewlinesContext context){return context.GetText();}public override string VisitStringtext(g4.TemplateParser.StringtextContext context){return context.GetText();}public override string VisitSimple_variable(g4.TemplateParser.Simple_variableContext context){return VisitSimple_variable_inner(context.simple_variable_inner());}public override string VisitComplex_variable(g4.TemplateParser.Complex_variableContext context){return VisitComplex_variable_inner(context.complex_variable_inner());}public override string VisitSimple_variable_inner(g4.TemplateParser.Simple_variable_innerContext context){string var_name = context.identity().GetText();if (!ctx.ContainsKey(var_name))throw new NullReferenceException(var_name);return Convert.ToString(ctx[var_name]);}public override string VisitComplex_variable_inner(g4.TemplateParser.Complex_variable_innerContext context){string var_name = context.identity()[0].GetText();if (!ctx.ContainsKey(var_name))throw new NullReferenceException(var_name);string propertyName = context.identity()[1].GetText();object obj = ctx[var_name];Type t = obj.GetType();PropertyInfo propertyInfo = t.GetProperty(propertyName);var value = propertyInfo.GetValue(obj, null);string string_value = Convert.ToString(value);return string_value;}}

    ?

    構造函數中傳入的ctx是我們要替換的變量集合

    光看這些函數是會暈的,你得結合eclipse中的解析樹層次圖來同時看,要清楚的知道上下關系,然后再套上面這個visit類才能看懂,呵呵,慢慢折騰看吧。

    ?

    此處等待數周。。。

    ?

    上面這個只是替換變量的沒意思,我們再做個有循環的,比如:

    your name: @{user.name} your age: @{user.age}1 23@{repeat 5} testing @{end repeat} --------------------- @{repeat count} testing @{end repeat}

    ?

    看,支持了循環repeat語法

    repeat后面可以支持固定的數字,也可以支持簡單變量,也可以支持復合變量,大家應該能在腦子里畫出規則形狀來吧。

    ?

    有興趣深入的同學可以自己試下實現if/else語法。

    ?

    代碼已經上傳到github上了,url:?https://github.com/daibinhua888/SimpleTemplate/

    ?

    轉載于:https://www.cnblogs.com/aarond/p/4856402.html

    總結

    以上是生活随笔為你收集整理的SimpleTemplate模板引擎开发的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。