日韩性视频-久久久蜜桃-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模板引擎开发的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 黄色av免费观看 | 亚洲日本网站 | 毛片免 | 日韩中文字幕一区二区 | 国产一道本| 国产成人精品免高潮费视频 | 自拍偷拍21p| 久草新视频 | 欧美全黄| 亚洲美女自拍 | 一区二区成人在线观看 | 国产乱国产乱老熟300部视频 | av电影网站在线观看 | 欧美精品一区二区久久婷婷 | 成人黄色av | 中国女人av| 亚洲色图 美腿丝袜 | 欧洲熟妇的性久久久久久 | 欧美日韩视频在线播放 | 亚洲av成人精品午夜一区二区 | 黄色网页免费看 | 翔田千里一区二区三区av | 中文激情网 | 中出在线 | 一区二区日韩国产 | 久久久久久免费 | 无码国产精品一区二区色情男同 | jk美女又爽又黄视频 | 她也啪在线视频 | 午夜精品久久久久久久蜜桃 | 欧美一级特黄aaaaaa | 桃色网址 | 欧美国产不卡 | 双性娇喘浑圆奶水h男男漫画 | 国产精品sm调教免费专区 | 亚洲精品乱码久久久久久蜜桃图片 | 92av视频 | 欧美69囗交视频 | 免费天堂av | 欧美成人a交片免费看 | 极品久久久久久 | 日本成人网址 | 中文字幕日韩精品亚洲一区小树林 | 三点尽露的大尺度国产 | 少妇4p| 午夜影院免费体验区 | 欧美日韩中文字幕一区二区三区 | 91传媒网站 | 激情五月激情综合 | 超碰97国产在线 | av一级在线观看 | 国产一区久久 | 亚洲Av无码成人精品区伊人 | 中文字幕一区二区三区在线播放 | 美女扒开粉嫩的尿囗给男生桶 | 久久99精品波多结衣一区 | 色免费看| 艳妇乳肉豪妇荡乳xxx | 中国大陆一级片 | 精品国产aⅴ一区二区三区东京热 | h片观看| 最新在线黄色网址 | 97久久国产亚洲精品超碰热 | av丁香| 97在线免费观看 | 一区二区自拍偷拍 | 日韩影院一区 | 国产精品扒开腿做爽爽爽男男 | 亚洲a色 | 日韩三级在线 | 一区二区三区久久久久 | 黄色精品| 欧美最猛黑人xxxx | 亚洲一区视频网站 | 色婷婷伊人 | 欧美综合激情 | 69黄色片 | 高清日韩av | 亚洲综合五月天 | 偷自在线 | 精品人妻久久久久久888不卡 | 欧美三级午夜理伦三级小说 | 日产国产亚洲精品系列 | 成人高清免费观看 | 91嫩草在线| 中文字幕av无码一区二区三区 | 日韩精品乱码久久久久久 | 污视频网站免费观看 | 午夜剧场免费看 | 精品国产乱码久久久久久88av | 凹凸日日摸日日碰夜夜 | 免费日韩在线视频 | 欧洲熟妇精品视频 | 欧美日韩亚洲在线观看 | 亚洲熟妇av一区二区三区 | 深夜在线网站 | 国产婷婷一区二区 | 中文字幕日韩亚洲 | 成人午夜精品无码区 |