2011-07-31 33 views
41

tôi đang cố gắng để tạo ra một tập tin cấu hình đơn giản mà trông như thế nàyTạo một file cấu hình đơn giản và phân tích cú pháp trong C++

url = http://mysite.com 
file = main.exe 
true = 0 

khi chương trình chạy, tôi muốn nó để tải các thiết lập cấu hình vào các biến chương trình được liệt kê dưới đây.

string url, file; 
bool true_false; 

Tôi đã làm một số nghiên cứu và this liên kết dường như giúp (bài nucleon của) nhưng tôi dường như không thể có được nó để làm việc và nó quá phức tạp để hiểu về một phần của tôi. Có cách đơn giản để làm điều này? Tôi có thể tải tập tin bằng cách sử dụng ifstream nhưng đó là như xa như tôi có thể nhận được trên của riêng tôi. Cảm ơn!

+4

Boost.program_options được lưu ý, hỗ trợ chuyển tiếp liền mạch từ các đối số dòng lệnh sang tệp cấu hình. –

+0

Tôi đã nghe rất nhiều về các thư viện tăng cường. Tôi có thể cung cấp cho họ một thử nhưng tôi đã hy vọng cho một cái gì đó đơn giản bằng cách sử dụng các hoạt động chuỗi. Tôi không có kế hoạch làm bất kỳ tập tin cấu hình nặng. – llk

+1

Bạn đã cân nhắc tạo tệp cấu hình của mình dưới dạng XML, vì vậy bạn không phải viết thủ công trình phân tích cú pháp chuỗi? Sau đó, bạn có thể sử dụng một trong vô số các thư viện XML được xuất hiện ở đó. – selbie

Trả lời

35

Nói chung, cách dễ nhất là phân tích các tệp cấu hình điển hình như vậy trong hai giai đoạn: đầu tiên đọc các dòng và sau đó phân tích cú pháp từng dòng một.
Trong C++, các dòng có thể được đọc từ một luồng bằng cách sử dụng std::getline(). Mặc dù nó sẽ đọc đến '\n' tiếp theo (mà nó sẽ tiêu thụ, nhưng không trả lại), bạn có thể chuyển nó qua một số dấu phân cách khác, điều này làm cho nó trở thành một ứng cử viên tốt cho việc đọc lên một số char, như = trong ví dụ của bạn.

Để đơn giản, những điều sau đây giả định rằng =không phải được bao quanh bởi khoảng trắng. Nếu bạn muốn cho phép khoảng trắng ở các vị trí này, bạn sẽ phải đặt chiến lược is >> std::ws trước khi đọc giá trị và xóa khoảng trắng theo sau khỏi các phím. Tuy nhiên, IMO thêm chút linh hoạt trong cú pháp không phải là giá trị phức tạp cho một trình đọc tập tin cấu hình.

const char config[] = "url=http://example.com\n" 
         "file=main.exe\n" 
         "true=0"; 

std::istringstream is_file(config); 

std::string line; 
while(std::getline(is_file, line)) 
{ 
    std::istringstream is_line(line); 
    std::string key; 
    if(std::getline(is_line, key, '=')) 
    { 
    std::string value; 
    if(std::getline(is_line, value)) 
     store_line(key, value); 
    } 
} 

(xử lý lỗi Thêm là trái như một bài tập cho người đọc.)

3

Tại sao không thử một cái gì đó đơn giản và dễ đọc, giống như JSON (hoặc XML)?

Có nhiều triển khai mã nguồn mở được tạo sẵn của JSON (hoặc XML) cho C++ - tôi sẽ sử dụng một trong số chúng.

Và nếu bạn muốn một cái gì đó nhiều hơn "nhị phân" - thử BJSON hoặc BSON :)

+7

JSON hoặc XML là máy có thể đọc được nhưng không thực sự có thể đọc được. – LtWorf

+2

JSON khá dễ đọc nếu bạn định dạng đúng (xem: https://docs.npmjs.com/files/package.json). XML ít đọc được hơn, nhưng cả hai đều được thiết kế để vừa có thể đọc được/có thể chỉnh sửa được. –

13

Một cách tiếp cận ngây thơ có thể trông như thế này:

#include <map> 
#include <sstream> 
#include <stdexcept> 
#include <string> 

std::map<std::string, std::string> options; // global? 

void parse(std::istream & cfgfile) 
{ 
    for (std::string line; std::getline(cfgfile, line);) 
    { 
     std::istringstream iss(line); 
     std::string id, eq, val; 

     bool error = false; 

     if (!(iss >> id)) 
     { 
      error = true; 
     } 
     else if (id[0] == '#') 
     { 
      continue; 
     } 
     else if (!(iss >> eq >> val >> std::ws) || eq != "=" || iss.get() != EOF) 
     { 
      error = true; 
     } 

     if (error) 
     { 
      // do something appropriate: throw, skip, warn, etc. 
     } 
     else 
     { 
      options[id] = val; 
     } 
    } 
} 

Bây giờ bạn có thể truy cập mỗi giá trị tùy chọn từ toàn cầu options bản đồ bất cứ nơi nào trong chương trình của bạn. Nếu bạn muốn castability, bạn có thể làm cho các loại bản đồ một boost::variant.

+0

Điều gì sẽ xảy ra nếu nhận xét có hơn 2 từ? Nó có hoạt động không? Có bỏ qua dòng này hay chỉ 2 chuỗi tiếp theo nếu 'id == '#''? – sop

+1

@sop: Vâng, đó là mã khá khủng khiếp. Tôi đã thực hiện một số cải tiến. [Demo] (http://ideone.com/evTjHO) –

+0

@sop: (Tôi không biết bất kỳ C++ nào sau đó ...) –

29

Như những người khác đã chỉ ra, nó có lẽ sẽ ít việc để làm cho việc sử dụng một thư viện phân tích cú pháp cấu hình file đang tồn tại thay vì phát minh lại bánh xe.Ví dụ, nếu bạn quyết định sử dụng thư viện Config4Cpp (mà tôi duy trì), cú pháp tệp cấu hình của bạn sẽ hơi khác (đặt dấu ngoặc kép xung quanh giá trị và chấm dứt câu lệnh gán bằng dấu chấm phẩy) như trong ví dụ bên dưới :

# File: someFile.cfg 
url = "http://mysite.com"; 
file = "main.exe"; 
true_false = "true"; 

các chương trình sau đây phân tích các tập tin cấu hình trên, bản sao các giá trị mong muốn vào các biến và in chúng:

#include <config4cpp/Configuration.h> 
#include <iostream> 
using namespace config4cpp; 
using namespace std; 

int main(int argc, char ** argv) 
{ 
    Configuration * cfg = Configuration::create(); 
    const char *  scope = ""; 
    const char *  configFile = "someFile.cfg"; 
    const char *  url; 
    const char *  file; 
    bool    true_false; 

    try { 
     cfg->parse(configFile); 
     url  = cfg->lookupString(scope, "url"); 
     file  = cfg->lookupString(scope, "file"); 
     true_false = cfg->lookupBoolean(scope, "true_false"); 
    } catch(const ConfigurationException & ex) { 
     cerr << ex.c_str() << endl; 
     cfg->destroy(); 
     return 1; 
    } 
    cout << "url=" << url << "; file=" << file 
     << "; true_false=" << true_false 
     << endl; 
    cfg->destroy(); 
    return 0; 
} 

các Config4Cpp website cung cấp Compr tài liệu hướng dẫn chi tiết, nhưng chỉ đọc Chương 2 và 3 của "Hướng dẫn bắt đầu" nên quá đủ cho nhu cầu của bạn.

+8

Chắc chắn rằng config4star của bạn đã có một repo git công cộng để tôi có thể sử dụng nó trong một dự án khác với một liên kết thay vì bao gồm mã thực tế ... – taxilian

+5

"Theo như tôi biết, Config4 * là trình phân tích cú pháp tệp cấu hình tốt nhất trên thế giới. Các công nghệ cạnh tranh (như XML, JSON, các thuộc tính Java, Windows Registry và vân vân) là tầm thường và đơn giản so sánh. " - Không tải xuống vì tuyên bố khăng khăng này trên trang web của bạn. – Zimano

2

Tôi đã tìm kiếm các thư viện phân tích cú pháp cấu hình cho dự án của tôi thời gian gần đây và tìm thấy các thư viện:

9

libconfig là rất dễ dàng, và những gì là tốt hơn, nó sử dụng một ký hiệu giả json để có thể đọc tốt hơn.

Dễ dàng để cài đặt trên Ubuntu: sudo apt-get install libconfig++8-dev

và liên kết: -lconfig++

0

Đây là một công việc đơn giản xung quanh cho khoảng trắng giữa dấu '=' và các dữ liệu, trong file config. Gán cho istringstream từ vị trí sau ký hiệu '=' và khi đọc từ nó, bất kỳ không gian trắng nào được bỏ qua.

Lưu ý: khi sử dụng istringstream trong vòng lặp, hãy đảm bảo bạn gọi rõ ràng() trước khi gán chuỗi mới cho chuỗi đó.

//config.txt 
//Input name = image1.png 
//Num. of rows = 100 
//Num. of cols = 150 

std::string ipName; 
int nR, nC; 

std::ifstream fin("config.txt"); 
std::string line; 
std::istringstream sin; 

while (std::getline(fin, line)) { 
sin.str(line.substr(line.find("=")+1)); 
if (line.find("Input name") != std::string::npos) { 
    std::cout<<"Input name "<<sin.str()<<std::endl; 
    sin >> ipName; 
} 
else if (line.find("Num. of rows") != std::string::npos) { 
    sin >> nR; 
} 
else if (line.find("Num. of cols") != std::string::npos) { 
    sin >> nC; 
} 
sin.clear(); 
} 
+0

tại sao tôi bị lỗi Phân đoạn (lõi bị bán) khi tôi sử dụng phương pháp của bạn? – enjal

+0

Đầu vào có trong biểu mẫu được hiển thị trong các nhận xét ở đầu đoạn mã của tôi không? – haripkannan

1

Cách định dạng cấu hình của bạn dưới dạng JSON và sử dụng thư viện như jsoncpp?

ví dụ:

{"url": "http://mysite dot com", 
"file": "main.exe", 
"true": 0} 

Sau đó bạn có thể đọc nó vào biến được đặt tên, hoặc thậm chí lưu trữ nó tất cả trong một std :: bản đồ vv Sau đó có nghĩa là bạn có thể thêm các tùy chọn mà không cần phải thay đổi và biên dịch lại phân tích cú pháp cấu hình của bạn.

Các vấn đề liên quan