解析器(一):分隔符指導
又是一個新的系列,那個什麼是「解析器」?在我的認知里,大概代表了如下的東西:
1、格式解析,將固定格式的字元串內容,翻譯成我們能夠簡單獲取和處理的結構;如配置文件(.ini)、XML。
2、編譯器+虛擬機,其實就是某一門語言的前端+後端+運行時,當然也可以解釋執行;如本人的Xmas,輕量的有正則表達式(Regex)。
所以,本系列是打算講述:配置文件(或許有Xml亂入)---正則表達式---Xmas(目前個人實現的最複雜的部分)。所以,接下來,回到本文的主題:
分隔符指導解析:使用固定字元進行語法分割的簡單的一種解析方式。
比如配置文件:
[GC.Mark]
MajorAge = 5
ElevateRatio = 5
MinorBytes = 2097152
MajorBytes = 104857600
[GC.Generation]
MajorAge = 5
SurvivorRatio = 5
MinorBytes = 2097152
MajorBytes = 10485760
FixedBytes = 1048576
上面就是最典型的配置文件的一部分。其中只有4個我們需要注意的【分隔字元】:
1、【[】,代表了一個條目的名字的開始
2、【]】,一個條目名字的結束,其後所有的內容都是該條目的鍵值對,直到遇到一個新的條目
3、【=】,鍵值對的分隔符,其前面的是鍵(key),後面的則是值(value)
4、【;】,注釋
當然還有一個隱式的分隔符:【
】換行符,所有的內容都以它作為結束;這一點至關重要:解析工作,可以以行為單位。
std::string context; 這樣,我們的工作對象,就將整個字元串減少到一行。 在這裡,我們可以預見:解析配置文件,是簡單而枯燥無味的;是的,的確如此: void parseLine(const std::string& line) 如此簡單地我們就完成了解析任務的最核心的部分;可惜的是,絲毫沒有任何難度和挑戰。當然,我們可以做一些優化工作: 1、考慮【]】的匹配,前面我們並沒有考慮它;只是默認,條目所在行的最後字元一定就是【]】;當然,這樣也才是正確的配置格式;但是,我們可以容錯,至於需要容許怎樣的錯誤,由自己喜好。 2、去空隔,特別是鍵值對,其中【=】的前後可能會有空格;我們有必要去掉它。
Files.read("config.ini", context);
std::vector
Strings.split(context.c_str, "
", lines);
for(auto& line, lines){
parseLine(line);
}
{
if(line == ""){
return;
}
if(line[0] == "["){
std::string item(&line[1], &line[line.length() - 1]);
setCurrentItem(item);//設置當前所處的條目環境
return;
}
if(line[0] == ";"){
return;
}
int offset = line.find("=");
if(offset < 0){
return;
}
std::string key(&line[0], &line[offset]);
std::string value(&line[offset + 1];
addValue(key, value);
}
3、更多的注釋支持,如:不止使用【;】、其位置可以不是每行的開始。
下一個問題,就是:這些解析出的信息,放在哪裡?
作為一個沒有難度和特色的ini解析器,我們可以這樣:
void setCurrentItem(const std::string& item)
{
mItem = item;
}
void addValue(const std::string& key, const std::string& value)
{
mValues[mItem + "." + key] = value;//注意這個「.」的作用
}
我們使用一個Map來存放鍵值對,而配置文件只有鍵值對。到此,我們基本上完成了所有的工作;只剩對外的查詢介面了。
我們支持怎樣的查詢?
來點有意思的如何:
String value(const String& name)const;
ItemList items(const String& name)const;
ValueList values(const String& name)const;
我個人的解析器,支持層級查詢:類似於文件目錄結構,一個層級內部有多個下一級層級和多個值(對應一個文件夾內部有多個文件夾和多個文件)。要仔細分析這句話:
1、有目錄結構,即:一個條目長這樣「GC.Mark」,意味著其有兩級對應的層次「GC」和它的下一級「Mark」(使用「.」作為層分隔)
2、有多個層級,即:我們的配置文件,其實是一棵樹(在當前定義下)
3、當前層級有多個值,而非鍵值對。
這樣,我們將支持這樣的格式:
[Xmas.Source]
H:XmasXmas.xmas
H:XmasTools.xmas
一個列表。當我使用如下代碼時:
sourceList = config.values("Xmas.Source");
它將返回一個字元串列表 ["H:XmasXmas.xmas", "H:XmasTools.xmas"]。
當我使用如下代碼時:
itemList = config.items("GC");
它將返回兩個條目:「Mark」、「Generation」。然後,沿著條目,我可以繼續向下遍歷:
class Item{
public:
String nameconst;
String valueconst;
String value(const String& name)const;
public:
ItemList itemsconst;
ValueList valuesconst;
};
通過該條目,我便可以像訪問一顆樹一樣。當然,這時該解析器內部正是構建了一個真正的DOM樹。
聰明的讀者應該發現我早已偏離了本文的主題:分隔符指導解析。是的,使用分隔符解析,是一種簡單且連入門都算不上的解析方式;但其作為一個指引,指向更完善的語法指導,還是有價值的。
在語法指導解析中,充滿了各種樹形結構;所以,我們必須了解、知道、精通,一棵樹的創建和訪問。而前面帶有層級的配置解析器,是一個不錯的開始。
※基於servlet和ajax的聊天室
※vue-router路由參數刷新消失的問題
※沒有main方法真的不能執行代碼了嗎?
※網頁標題(title)動態改變
※「Open Source」負載均衡之Nginx
TAG:達人科技 |
※2018 ESC暈厥診斷與處理指南臨床實踐指導:第一部分(名詞解釋)
※CA測試儀錶指導及問題分析
※2018 ESC 暈厥診斷與處理指南臨床實踐指導:第二部分(初步評估)
※寫作指導:一個「抄襲」的技巧
※2018 ESC 暈厥診斷與處理指南臨床實踐指導:短暫意識喪失的病史要點(第三部分)
※2018 ESC 暈厥診斷與處理指南臨床實踐指導:第四部分(頸動脈竇按摩)
※【寫作指導】文題集萃【2】
※單節7中6狂飆18分 看盧指導和樂福的表情:又被一個庫里支配了
※詩詞寫作指導:《點絳唇》寫作指南
※許強老師:分享議論文指導中的弟子習作
※2018 ESC 暈厥診斷與處理指南臨床實踐指導(第六部分):直立傾斜試驗
※中興LTE抓包分析指導手冊
※【真傳一刻】第221期:史強-傷寒體系對臨證的指導(中)
※2018 ESC 暈厥診斷與處理指南臨床實踐指導(第八部分):血管迷走性暈厥的治療
※2018 ESC 暈厥診斷與處理指南臨床實踐指導(第七部分):植入式循環記錄儀
※詩詞寫作指導:押韻十三忌
※【真傳一刻】第220期:史強-傷寒體系對臨證的指導(上)
※十分鐘通氣血,每天1次,腰酸背痛立馬緩解(動圖指導)
※玫瑰花頭上點、胡片:病害詳細講解及防治指導
※時評文寫作指導