2016-09-21 96 views
1

我在寫一個涉及boost :: program_options的C++程序,在這裏我遇到了一些問題。我的一些代碼在這裏給出。使用boost program_options處理幫助消息,刪除默認值或重新格式化幫助消息

int main(int argc, char* argv[]) { 
    options_description desc("useage: filterfq", options_description::m_default_line_length * 2, options_description::m_default_line_length); 

    options_description generic("Gerneric options", options_description::m_default_line_length * 2, options_description::m_default_line_length); 
    generic.add_options() 
     ("help,h", "produce help message") 
    ; 

    options_description param("Parameters", options_description::m_default_line_length * 2, options_description::m_default_line_length); 
    param.add_options() 
     ("checkQualitySystem,c", bool_switch(), "only check quality system of the fastq file") 
     ("baseNrate,N", value<float>() -> default_value(0.05), "maximum rate of \'N\' base allowed along a read") 
     ("averageQuality,Q", value<float>() -> default_value(0), "minimum average quality allowed along a read") 
     ("perBaseQuality,q", value<int>() -> default_value(5), "minimum quality per base allowed along a read") 
     ("lowQualityRate,r", value<float>() -> default_value(0.5), "maximum low quality rate along a read") 
     ("rawQualitySystem,s", value<int>(), "specify quality system of raw fastq\n0: Sanger\n1: Solexa\n2: Illumina 1.3+\n3: Illumina 1.5+\n4: Illumina 1.8+") 
     ("preferSpecifiedRawQualitySystem,p", bool_switch(), "indicate that user prefers the given quality system to process") 
    ; 

    options_description input("Input", options_description::m_default_line_length * 2, options_description::m_default_line_length); 
    input.add_options() 
     ("rawFastq,f", value< vector<path> >() -> required() -> multitoken(), "raw fastq file(s) that need cleaned, required") 
    ; 

    options_description output("Output", options_description::m_default_line_length * 2, options_description::m_default_line_length); 
    output.add_options() 
     ("cleanQualitySystem,S", value<int>() -> default_value(4), "specify quality system of cleaned fastq, the same as rawQualitySystem") 
     ("outDir,O", value<path>() -> default_value(current_path()), "specify output directory, not used if cleanFastq is specified") 
     ("outBasename,o", value<string>(), "specify the basename for output file(s), required if outDir is specified") 
     ("cleanFastq,F", value< vector<path> >() -> multitoken(), "cleaned fastq file name(s), not used if outDir or outBasename is specified") 
     ("droppedFastq,D", value< vector<path> >() -> multitoken(), "fastq file(s) containing reads that are filtered out") 
    ; 

    desc.add(generic).add(param).add(input).add(output); 

    variables_map vm; 
    store(command_line_parser(argc, argv).options(desc).run(), vm); 
    if (vm.count("help")) { 
     cout << desc << "\n"; 
     return 0; 
    } 
    ... 
} 

#include using namespace parts are not given here。當我輸入的命令來查看幫助信息,它表明我下面

useage: filterfq: 

Gerneric options: 
    -h [ --help ]   produce help message 

Parameters: 
    -c [ --checkQualitySystem ]    only check quality system of the fastq file 
    -N [ --baseNrate ] arg (=0.0500000007) maximum rate of 'N' base allowed along a read 
    -Q [ --averageQuality ] arg (=0)   minimum average quality allowed along a read 
    -q [ --perBaseQuality ] arg (=5)   minimum quality per base allowed along a read 
    -r [ --lowQualityRate ] arg (=0.5)  maximum low quality rate along a read 
    -s [ --rawQualitySystem ] arg    specify quality system of raw fastq 
              0: Sanger 
              1: Solexa 
              2: Illumina 1.3+ 
              3: Illumina 1.5+ 
              4: Illumina 1.8+ 
    -p [ --preferSpecifiedRawQualitySystem ] indicate that user prefers the given quality system to process 

Input: 
    -f [ --rawFastq ] arg raw fastq file(s) that need cleaned, required 

Output: 
    -S [ --cleanQualitySystem ] arg (=4)    specify quality system of cleaned fastq, the same as rawQualitySystem 
    -O [ --outDir ] arg (="/home/tanbowen/filterfq") specify output directory, not used if cleanFastq is specified 
    -o [ --outBasename ] arg       specify the basename for output file(s), required if outDir is specified 
    -F [ --cleanFastq ] arg       cleaned fastq file name(s), not used if outDir or outBasename is specified 
    -D [ --droppedFastq ] arg      fastq file(s) containing reads that are filtered out 

幫助消息看起來有點醜,尤其是「0.0500000007」,我想改善它。但我搜索了很長時間,我找不到解決方案。所以我在這裏尋求幫助解決以下問題:

  1. 有什麼方法可以重新格式化幫助信息嗎?
  2. 如果1不可能,如何刪除「arg」部分和默認值?
  3. 是否有任何方法來對齊右側的描述?

一個額外的問題:我如何才能防止被執行

filter -f <some file> -f <some file> 

即不允許被多次指定相同的選項下面的命令?

非常感謝!

+0

如果你program_options文檔中仔細搜尋它提到製作自定義類接收選項值。你爲這個類編寫operator <<和operator >>。然後你可以按照你的意願格式化它。 –

回答

2
  1. 是的,見下文(示出了收集和顯示格式的選項的一般形式)

  2. 看的options_description構造。它允許你指定列的寬度。

以下是自定義選項值的(實際)示例。在我的情況下,我想收集以字節爲單位的緩衝區大小,但也希望能夠解析像4K或1M的東西。

struct bytesize_option 
{ 
    bytesize_option(std::size_t val = 0) : _size(val) {} 

    std::size_t value() const { return _size; } 
    void set(std::size_t val) { _size = val; } 

private: 
    std::size_t _size; 
}; 

std::ostream& operator<<(std::ostream& os, bytesize_option const& hs); 
std::istream& operator>>(std::istream& is, bytesize_option& hs); 

namespace { 
    static constexpr auto G = std::size_t(1024 * 1024 * 1024); 
    static constexpr auto M = std::size_t(1024 * 1024); 
    static constexpr auto K = std::size_t(1024); 
} 

std::ostream& operator<<(std::ostream& os, bytesize_option const& hs) 
{ 
    auto v = hs.value(); 
    if (v % G == 0) { return os << (v/G) << 'G'; } 
    if (v % M == 0) { return os << (v/M) << 'M'; } 
    if (v % K == 0) { return os << (v/K) << 'K'; } 
    return os << v; 
} 

std::istream& operator>>(std::istream& is, bytesize_option& hs) 
{ 
    std::string s; 
    is >> s; 
    static const std::regex re(R"regex((\d+)([GMKgmk]){0,1})regex"); 
    std::smatch match; 
    auto matched = std::regex_match(s, match, re); 
    if(!matched) { 
     throw po::validation_error(po::validation_error::invalid_option_value); 
    } 
    if (match[2].matched) 
    { 
     switch (match[2].str().at(0)) 
     { 
      case 'G': 
      case 'g': 
       hs.set(std::stoul(match[1].str()) * G); 
       break; 
      case 'M': 
      case 'm': 
       hs.set(std::stoul(match[1].str()) * M); 
       break; 
      case 'K': 
      case 'k': 
       hs.set(std::stoul(match[1].str()) * K); 
       break; 
     } 
    } 
    else { 
     hs.set(std::stoul(match[1].str())); 
    } 
    return is; 
} 

你會使用它,像這樣:

return boost::shared_ptr<po::option_description> { 
     new po::option_description("server.max-header-size,x", 
            po::value(&_max_hdr_size) 
            ->default_value(_max_hdr_size), 
            "The maximum size (in bytes) of a HTTP header " 
            "that the server will accept") 
    }; 

凡在此情況下,_max_hdr_size定義:

bytesize_option _max_hdr_size; 
+0

我試圖在options_description構造函數中給出兩個與列寬有關的參數,就像上面給出的代碼一樣,但它不起作用。它仍然沒有對齊。 –