2010-08-17 4 views
4

Я работаю над личным проектом, который использует настраиваемый файл конфигурации. Основной формат файла выглядит следующим образом:Каков наилучший способ проанализировать этот файл конфигурации?

[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. Может ли кто-нибудь, возможно, предоставить лучший способ или подход, который не так запутан, как мой?

+1

Я просто добавлю это как комментарий, так как я не отвечаю на ваш вопрос относительно этой конфигурации конфигурации. Поскольку это личный проект, можно ли изменить его на нечто вроде XML? Тогда вы можете использовать что-то вроде JAXP. – JBirch

+1

Что это такое с разработчиками Java и XML? Предложение Cletus YAML - это место, потому что это то, что больше похоже на конфигурацию OP. Вы бы это знали, если бы вы расширили горизонты через Ruby on Rails или даже в PHP-инфраструктуру Symfony. Я тоже разработчик Java, и эта постоянная зависимость от XML большинством других разработчиков Java находится где-то между комическим и жалким. Я когда-то показал структуру микро MVC, которую я разработал для Java-архитектора, и он заметил «Where's mapping», которым он имел в виду XML. Лучший вопрос: почему нельзя использовать другие форматы для заполнения карт (ping)? –

+0

В нескольких комментариях вы указываете, что скобки, скобки, кавычки и т. Д. Стандартных форматов слишком много беспорядка. Я просто хотел указать, что есть веская причина для этого «беспорядка». В настоящее время вы зависите от вкладок, которые действительно хрупкие. Что происходит, когда кто-то открывает файл конфигурации в том, что преобразует вкладки в пробелы? Минимально вы также должны поддерживать пробелы. –

ответ

3

Каждый рекомендуется использовать XML, потому что это просто лучше.

Однако, в случае, если вы находитесь на поиски, чтобы доказать ценность своего программиста к себе ...

... нет ничего на самом деле в корне неправильно с кодом вы публикуемую в том смысле, что это ясно, и очевидным для потенциальных читателей, что происходит, и, если я не полностью выхожу из цикла при работе с файлами, он должен выполняться в значительной степени, как мог.

Единственная критика, которую я мог бы предложить, заключается в том, что она не рекурсивна. Для каждого уровня требуется новый уровень поддержки кода. Я бы, вероятно, сделал рекурсивную функцию (функцию, которая вызывает себя с суб-содержимым в качестве параметра, а затем снова, если есть суб-суб-контент и т. Д.), Который можно было бы назвать, прочитав все это в хэш-таблицу с хэш-таблицами или что-то еще , а затем я использую эту хеш-таблицу в качестве объекта конфигурации.

С другой стороны, в этот момент я, вероятно, перестану видеть точку и использовать XML. ;)

+0

Спасибо за ответ Хельги. Цитата: «Однако, если вы в поиске, чтобы доказать ценность вашего программиста для себя ...», в этом случае была довольно применима. Я рассмотрю ваш совет о том, чтобы сделать это более рекурсивным. До сих пор ваш пост был самым полезным для меня, но я подожду еще немного, прежде чем я сделаю этот ответ;) – trinth

6

Я бы предложил не создавать настраиваемый код для файлов конфигурации. То, что вы предлагаете, не слишком далеко от YAML (getting started). Используйте это вместо этого.

См Which java YAML library should I use?

+0

Как прокомментировал ответ codemeit, вначале я рассматривал YAML, но файл конфигурации был чрезвычайно упрощенным. – trinth

+0

@trinth Я не знаю, почему именно вы думаете, что YAML - тяжеловес. Это так же легко, как и ваши данные. Я придерживаюсь своей рекомендации; лучше поместить ваши данные в существующую модель, чем без необходимости изобретать собственный формат конфигурации с соответствующими библиотеками. – cletus

2

Если вы можете использовать XML или JSON или другие известное кодирование данных в качестве формата данных, то это будет намного проще разобрать/десериализацию содержания текста и извлечение значений. Например, .

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

может быть выражен как последующие X (есть и другие варианты, чтобы выразить это в 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 

, а затем сделать строку раскол на «\ п» (символ новой строки) и «:», чтобы извлечь ключ и значение или построить объект словарь/карту.

+0

Формат данных OP выглядит замечательно, как YAML. Все другие предлагаемые форматы данных являются спорными. –

+1

Да, я первоначально выбрал YAML для проекта, однако я не думал, что синтаксис будет уместным. Файл конфигурации должен быть таким же упрощенным, как и XML, и JSON был слишком многословным, и YAML все еще не делал разреза. – trinth

+0

В этом случае вы можете просто указать им все имя и пару значений. , например. имя: bob; attributes_hat: brown; attributes_shirt: black; another_section_key: значение; another_section_key2: value2 , а затем строка разделена на ';' и ':' –

1

Я бы рекомендовал изменить формат файла конфигурации на JSON и использовать существующую библиотеку для анализа объектов JSON, таких как FlexJSON.

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

}

+0

id любят использовать json, но скобки, скобки и кавычки слишком много беспорядка, и я хотел бы сохранить простой файл конфигурации. – trinth

+2

Я понимаю. Что делать, если вы выбираете стандартный формат файла (например, JSON или XML), но вместо этого предоставляете пользовательский интерфейс для редактирования файла? Таким образом, вы можете скрыть сложность от своих пользователей, упростить ее и снизить затраты на техническое обслуживание сверхурочно. Более того, это позволит вашим пользователям сосредоточиться на данных вместо синтаксиса файла конфигурации. – johnnieb

2

Это выглядит достаточно просто для конечного автомата.

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. 
1

Хорошим способом его очистки было бы использовать таблицу, то есть заменить ваши условные обозначения на карту. Затем вы можете вызвать методы анализа методом отражения (простое) или создать еще несколько классов, реализующих общий интерфейс (больше работы, но более надежной).

Смежные вопросы