當前位置:
首頁 > 知識 > 解析器(一):分隔符指導

解析器(一):分隔符指導

又是一個新的系列,那個什麼是「解析器」?在我的認知里,大概代表了如下的東西:

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;
Files.read("config.ini", context);
std::vector lines;
Strings.split(context.c_str, "
", lines);
for(auto& line, lines){
parseLine(line);
}

這樣,我們的工作對象,就將整個字元串減少到一行。

在這裡,我們可以預見:解析配置文件,是簡單而枯燥無味的;是的,的確如此:

void parseLine(const std::string& 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); }

如此簡單地我們就完成了解析任務的最核心的部分;可惜的是,絲毫沒有任何難度和挑戰。當然,我們可以做一些優化工作:

1、考慮【]】的匹配,前面我們並沒有考慮它;只是默認,條目所在行的最後字元一定就是【]】;當然,這樣也才是正確的配置格式;但是,我們可以容錯,至於需要容許怎樣的錯誤,由自己喜好。

2、去空隔,特別是鍵值對,其中【=】的前後可能會有空格;我們有必要去掉它。

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次,腰酸背痛立馬緩解(動圖指導)
玫瑰花頭上點、胡片:病害詳細講解及防治指導
時評文寫作指導