簡體   English   中英

解析此配置文件的最佳方法是什么?

[英]What is the best way to parse this configuration file?

我正在開發一個使用自定義配置文件的個人項目。 該文件的基本格式如下所示:

[users]
name: bob
attributes:
    hat: brown
    shirt: black
another_section:
    key: value
    key2: value2

name: sally
sex: female
attributes:
    pants: yellow
    shirt: red

可以有任意數量的用戶,每個用戶可以有不同的鍵/值對,並且可以使用制表位在一個節下面嵌套鍵/值。 我知道我可以為這個配置文件使用json,yaml甚至xml,但是,我現在想保持自定義。

解析應該不難,因為我已經編寫了解析它的代碼。 我的問題是,使用干凈結構化的代碼解析這個問題的最佳方法是什么,以及在未來不會發生變化的方式編寫(未來可能會有多個嵌套)。 現在,我的代碼看起來非常惡心。 例如,

private void parseDocument() {  
    String current;
    while((current = reader.readLine()) != null) {
        if(current.equals("") || current.startsWith("#")) {
            continue; //comment
        } 
        else if(current.startsWith("[users]")) {
            parseUsers();
        }
        else if(current.startsWith("[backgrounds]")) {
            parseBackgrounds();
        }
    }
}

private void parseUsers()  {        
    String current;
    while((current = reader.readLine()) != null) {
        if(current.startsWith("attributes:")) {
            while((current = reader.readLine()) != null) {
                if(current.startsWith("\t")) {
                    //add user key/values to User object
                }
                else if(current.startsWith("another_section:")) {
                    while((current = reader.readLine()) != null) {
                        if(current.startsWith("\t")) {
                            //add user key/values to new User object
                        } 
                        else if (current.equals("")) {
                            //newline means that a new user is up to parse next
                        }
                    }
                }
            }
        }
        else if(!current.isEmpty()) {
            //
        }


    }
}

正如你所看到的,代碼非常混亂,我在這里簡化了演示。 我覺得有更好的方法可以做到這一點,也許不使用BufferedReader。 有人可以提供一種更好的方式或方法,而不是像我的那樣復雜嗎?

我建議不要為配置文件創建自定義代碼。 你提出的建議與YAML入門 )相差無幾 改用它。

請參閱我應該使用哪個Java YAML庫?

每個人都會建議使用XML,因為它更好。

但是,如果您正在尋求證明您的程序員對自己的價值......

......你發布的代碼沒有任何根本性的錯誤,因為它很清楚,對於潛在的讀者而言顯而易見的是,除非我完全脫離文件操作的循環,它應該表現得非常好盡可能的。

我能提出的一個批評是它不是遞歸的。 每個級別都需要支持新級別的代碼。 我可能會做一個遞歸函數(一個用子內容作為參數調用自身的函數,然后再調用子子內容等),可以調用,將所有這些東西讀入帶有哈希表的哈希表中,然后我將該哈希表用作配置對象。

然后,在那一點上,我可能會停止看到這一點並使用XML。 ;)

如果您可以使用XML或JSON或其他眾所周知的數據編碼作為數據格式,則解析/反序列化文本內容並提取值將更加容易。 例如。

name: bob
attributes:
    hat: brown
    shirt: black
another_section:
    key: value
    key2: value2

可以表示為以下XML(還有其他選項可以用XML表示)

<config>
  <User hat="brown" shirt="black" >
    <another_section>
      <key>value</key>
      <key2>value</key2>
    </another_section>
  </User>
</config>

自定義(非常簡單)正如我在下面的評論中提到的,您可以將它們全部設置為名稱和值對。 例如

name                 :bob
attributes_hat       :brown
attributes_shirt     :black
another_section_key  :value
another_section_key2 :value2

然后在'\\ n'(換行符)和':'上進行字符串拆分以提取鍵和值或構建字典/地圖對象。

對於狀態機而言看起來很簡單。

while((current = reader.readLine()) != null) {
  if(current.startsWith("[users]"))
    state = PARSE_USER;
  else if(current.startsWith("[backgrounds]"))
    state = PARSE_BACKGROUND;
  else if (current.equals("")) {
    // Store the user or background that you've been building up if you have one.
    switch(state) {
      case PARSE_USER:
      case USER_ATTRIBUTES:
      case USER_OTHER_ATTRIBUTES:
        state = PARSE_USER;
        break;
      case PARSE_BACKGROUND:
      case BACKGROUND_ATTRIBUTES:
      case BACKGROUND_OTHER_ATTRIBUTES:
        state = PARSE_BACKGROUND;
        break;
    }
  } else switch(state) {
    case PARSE_USER:
    case USER_ATTRIBUTES:
    case USER_OTHER_ATTRIBUTES:
      if(current.startsWith("attributes:"))
        state = USER_ATTRIBUTES;
      else if(current.startsWith("another_section:"))
        state = USER_OTHER_ATTRIBUTES;
      else {
        // Split the line into key/value and store into user
        // object being built up as appropriate based on state.
      }
      break;
    case PARSE_BACKGROUND:
    case BACKGROUND_ATTRIBUTES:
    case BACKGROUND_OTHER_ATTRIBUTES:
      if(current.startsWith("attributes:"))
        state = BACKGROUND_ATTRIBUTES;
      else if(current.startsWith("another_section:"))
        state = BACKGROUND_OTHER_ATTRIBUTES;
      else {
        // Split the line into key/value and store into background
        // object being built up as appropriate based on state.
      }
      break;
  }
}
// If you have an unstored object, store it.

我建議將配置文件的格式更改為JSON,並使用現有的庫來解析諸如FlexJSON之類的JSON對象。

{
"users": [
    {
        "name": "bob",
        "hat": "brown",
        "shirt": "black",
        "another_section": {
            "key": "value",
            "key2": "value2" 
        } 
    },
    {
        "name": "sally",
        "sex": "female",
        "another_section": {
            "pants": "yellow",
            "shirt": "red" 
        } 
    } 
] 

}

一個很好的清理方法是使用一個表,即用Map替換你的條件。 然后,您可以通過反射(簡單)調用解析方法,或者創建一些實現公共接口的類(更多工作但更強大)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM