一个不错的命令行解析类

简介:
原文链接:Command line parser



 作者所考虑的语法是:
 复制代码
CommandLine::=[<Key> [,<Key>]]
<Key>::=<Delimeter>KeyName[<Separator><Value>]
<Value> ::= { KeyValue | <QuoteChar>Quoted Key Value<QuoteChar>} ][
<Delimeter>::= { - | / }
<Separator>::= { : }
<QuoteChar>::= { " }

复制代码


复制代码

typedef CString CCmdLineParser_String ;

#include <map>
using std::map;


class CCmdLineParser 
{
public:
    class CValsMap : public map<CCmdLineParser_String, CCmdLineParser_String> {};//存储关键字--值对
    typedef CValsMap::const_iterator POSITION;//迭代器
public:
    CCmdLineParser(LPCTSTR sCmdLine = NULL, bool bCaseSensitive = false);//默认大小写不敏感
    virtual ~CCmdLineParser();

    bool Parse(LPCTSTR sCmdLine);//解析命令行

    LPCTSTR getCmdLine() const { return m_sCmdLine; }

    void setCaseSensitive(bool bSensitive) { m_bCaseSensitive = bSensitive; }
    bool getCaseSensitive() const { return m_bCaseSensitive; }

    const CValsMap& getVals() const { return m_ValsMap; }

    // Start iterating through keys and values
    POSITION getFirst() const;//第一个
    // Get next key-value pair, returns empty sKey if end reached
    POSITION getNext(POSITION& pos, CCmdLineParser_String& sKey, CCmdLineParser_String& sValue) const;//迭代器往后
    // just helper ;)
    bool isLast(POSITION& pos) const;//是否是最后一个

    // TRUE if "Key" present in command line
    bool HasKey(LPCTSTR sKey) const;//是否包含指定关键字
    // Is "key" present in command line and have some value
    bool HasVal(LPCTSTR sKey) const;//是否包含指定值
    // Returns value if value was found or NULL otherwise
    LPCTSTR GetVal(LPCTSTR sKey) const;//获取值
    // Returns true if value was found
    bool GetVal(LPCTSTR sKey, CCmdLineParser_String& sValue) const;

private:
    CValsMap::const_iterator findKey(LPCTSTR sKey) const;//查找指定关键字
private:
    CCmdLineParser_String m_sCmdLine;
    CValsMap    m_ValsMap;
    bool m_bCaseSensitive;

    static const TCHAR m_sDelimeters[];
    static const TCHAR m_sValueSep[];
    static const TCHAR m_sQuotes[];
};

复制代码

复制代码
const TCHAR CCmdLineParser::m_sDelimeters[] = _T("-/");//键的起始符
const TCHAR CCmdLineParser::m_sQuotes[] = _T("\"");    // Can be _T("\"\'"),  for instance
const TCHAR CCmdLineParser::m_sValueSep[] = _T(" :"); // Space MUST be in set 键值分隔符

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCmdLineParser::CCmdLineParser(LPCTSTR sCmdLine, bool bCaseSensitive)
: m_bCaseSensitive(bCaseSensitive)
{
    if(sCmdLine) 
    {
        Parse(sCmdLine);
    }
}

CCmdLineParser::~CCmdLineParser()
{
    m_ValsMap.clear();
}

bool CCmdLineParser::Parse(LPCTSTR sCmdLine) 
{
    if(!sCmdLine) return false;
    
    m_sCmdLine = sCmdLine;
    m_ValsMap.clear();
    const CCmdLineParser_String sEmpty;

    int nArgs = 0;
    LPCTSTR sCurrent = sCmdLine;
    while(true) {
        // /Key:"arg"
        if(_tcslen(sCurrent) == 0) { break; } // No data left
        LPCTSTR sArg = _tcspbrk(sCurrent, m_sDelimeters);
        if(!sArg) break; // No delimeters found
        sArg =  _tcsinc(sArg);
        // Key:"arg"
        if(_tcslen(sArg) == 0) break; // String ends with delimeter
        LPCTSTR sVal = _tcspbrk(sArg, m_sValueSep);
        if(sVal == NULL) { //Key ends command line
            CCmdLineParser_String csKey(sArg);
            if(!m_bCaseSensitive) {
                csKey.MakeLower();
            }
            m_ValsMap.insert(CValsMap::value_type(csKey, sEmpty));
            break;
        } else if(sVal[0] == _T(' ') || _tcslen(sVal) == 1 ) { // Key with no value or cmdline ends with /Key:
            CCmdLineParser_String csKey(sArg, sVal - sArg);
            if(!csKey.IsEmpty()) { // Prevent /: case
                if(!m_bCaseSensitive) {
                    csKey.MakeLower();
                }
                m_ValsMap.insert(CValsMap::value_type(csKey, sEmpty));
            }
            sCurrent = _tcsinc(sVal);
            continue;
        } else { // Key with value
            CCmdLineParser_String csKey(sArg, sVal - sArg);
            if(!m_bCaseSensitive) {
                csKey.MakeLower();
            }

            sVal = _tcsinc(sVal);
            // "arg"
            LPCTSTR sQuote = _tcspbrk(sVal, m_sQuotes), sEndQuote(NULL);
            if(sQuote == sVal) { // Quoted String
                sQuote = _tcsinc(sVal);
                sEndQuote = _tcspbrk(sQuote, m_sQuotes);
            } else {
                sQuote = sVal;
                sEndQuote = _tcschr(sQuote, _T(' '));
            }

            if(sEndQuote == NULL) { // No end quotes or terminating space, take rest of string
                CCmdLineParser_String csVal(sQuote);
                if(!csKey.IsEmpty()) { // Prevent /:val case
                    m_ValsMap.insert(CValsMap::value_type(csKey, csVal));//保存
                }
                break;
            } else { // End quote or space present
                if(!csKey.IsEmpty()) {    // Prevent /:"val" case
                    CCmdLineParser_String csVal(sQuote, sEndQuote - sQuote);
                    m_ValsMap.insert(CValsMap::value_type(csKey, csVal));
                }
                sCurrent = _tcsinc(sEndQuote);
                continue;
            }
        }

    }
    
    return (nArgs > 0);
}

CCmdLineParser::CValsMap::const_iterator CCmdLineParser::findKey(LPCTSTR sKey) const 
{
    CCmdLineParser_String s(sKey);
    if(!m_bCaseSensitive) {
        s.MakeLower();
    }
    return m_ValsMap.find(s);
}
// TRUE if "Key" present in command line
bool CCmdLineParser::HasKey(LPCTSTR sKey) const 
{
    CValsMap::const_iterator it = findKey(sKey);
    if(it == m_ValsMap.end()) return false;
    return true;
}

// Is "key" present in command line and have some value
bool CCmdLineParser::HasVal(LPCTSTR sKey) const 
{
    CValsMap::const_iterator it = findKey(sKey);
    if(it == m_ValsMap.end()) return false;
    if(it->second.IsEmpty()) return false;
    return true;
}
// Returns value if value was found or NULL otherwise
LPCTSTR CCmdLineParser::GetVal(LPCTSTR sKey) const 
{
    CValsMap::const_iterator it = findKey(sKey);
    if(it == m_ValsMap.end()) return false;
    return LPCTSTR(it->second);
}
// Returns true if value was found
bool CCmdLineParser::GetVal(LPCTSTR sKey, CCmdLineParser_String& sValue) const 
{
    CValsMap::const_iterator it = findKey(sKey);
    if(it == m_ValsMap.end()) return false;
    sValue = it->second;
    return true;
}

CCmdLineParser::POSITION CCmdLineParser::getFirst() const 
{
    return m_ValsMap.begin();
}
CCmdLineParser::POSITION CCmdLineParser::getNext(POSITION& pos, CCmdLineParser_String& sKey, CCmdLineParser_String& sValue) const 
{
    if(isLast(pos)) {
        sKey.Empty();
        return pos;
    } else {
        sKey = pos->first;
        sValue = pos->second;
        pos ++;
        return pos;
    }
}
// just helper ;)
bool CCmdLineParser::isLast(POSITION& pos) const
{
    return (pos == m_ValsMap.end());
}


复制代码

复制代码
#include "stdafx.h"
#include "cmdlineparser.h"

int main(int argc, char* argv[])
{
    CCmdLineParser parser(_T("/Key1 /Key2: -Key3:Val3 -Key4:\"Val 4-with/spaces/and-delimeters\" /Key5:Val5"));

    ASSERT(parser.HasKey(_T("Key1")) == true);
    ASSERT(parser.HasKey(_T("Key10")) == false);
    ASSERT(parser.HasVal(_T("Key2")) == false);
    ASSERT(parser.HasKey(_T("Key5"))==true);
    _tprintf(_T("==================== Test Parser ====================\n"));
    _tprintf(_T("Command line: [%s]\n"), parser.getCmdLine());//获取命令行参数
    _tprintf(_T("Key1 has value: [%s]\n"), parser.GetVal(_T("Key1")));// -> []; //(empty string)
    _tprintf(_T("Key2 has value: [%s]\n"), parser.GetVal(_T("Key2")));// -> []; 
    _tprintf(_T("Key3 has value: [%s]\n"), parser.GetVal(_T("Key3")));// -> [Val3];
    _tprintf(_T("Key4 has value: [%s]\n"), parser.GetVal(_T("Key4")));// -> [Val 4-with/spaces/and-delimeters];
    _tprintf(_T("Key5 has value: [%s]\n"), parser.GetVal(_T("Key5")));// -> []; //(empty string)

    _tprintf(_T("\n================= Real Command Line =================\n"));
    CCmdLineParser realParser(::GetCommandLine());
    CCmdLineParser::POSITION pos = realParser.getFirst();    
    CString sKey, sVal;
    while(!realParser.isLast(pos)) 
    {
        realParser.getNext(pos, sKey, sVal);
        _tprintf(_T("Key: [%s], Val: [%s]\n"), sKey, sVal);
    }
    system("pause");
    return 0;
}

复制代码



本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2008/06/28/1231628.html,如需转载请自行联系原作者
目录
相关文章
|
7月前
|
Java 开发者
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
240 0
|
8月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
10月前
|
数据可视化 数据挖掘 BI
团队管理者必读:高效看板类协同软件的功能解析
在现代职场中,团队协作的效率直接影响项目成败。看板类协同软件通过可视化界面,帮助团队清晰规划任务、追踪进度,提高协作效率。本文介绍看板类软件的优势,并推荐五款优质工具:板栗看板、Trello、Monday.com、ClickUp 和 Asana,助力团队实现高效管理。
195 2
|
12月前
|
安全 编译器 程序员
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
229 2
|
7月前
|
存储 监控 安全
重学Java基础篇—类的生命周期深度解析
本文全面解析了Java类的生命周期,涵盖加载、验证、准备、解析、初始化、使用及卸载七个关键阶段。通过分阶段执行机制详解(如加载阶段的触发条件与技术实现),结合方法调用机制、内存回收保护等使用阶段特性,以及卸载条件和特殊场景处理,帮助开发者深入理解JVM运作原理。同时,文章探讨了性能优化建议、典型异常处理及新一代JVM特性(如元空间与模块化系统)。总结中强调安全优先、延迟加载与动态扩展的设计思想,并提供开发建议与进阶方向,助力解决性能调优、内存泄漏排查及框架设计等问题。
270 5
|
7月前
|
安全 IDE Java
重学Java基础篇—Java Object类常用方法深度解析
Java中,Object类作为所有类的超类,提供了多个核心方法以支持对象的基本行为。其中,`toString()`用于对象的字符串表示,重写时应包含关键信息;`equals()`与`hashCode()`需成对重写,确保对象等价判断的一致性;`getClass()`用于运行时类型识别;`clone()`实现对象复制,需区分浅拷贝与深拷贝;`wait()/notify()`支持线程协作。此外,`finalize()`已过时,建议使用更安全的资源管理方式。合理运用这些方法,并遵循最佳实践,可提升代码质量与健壮性。
195 1
|
7月前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
257 5
|
8月前
|
Java 数据库 开发者
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
820 12
|
7月前
|
机器学习/深度学习 人工智能 监控
鸿蒙赋能智慧物流:AI类目标签技术深度解析与实践
在数字化浪潮下,物流行业面临变革,传统模式的局限性凸显。AI技术为物流转型升级注入动力。本文聚焦HarmonyOS NEXT API 12及以上版本,探讨如何利用AI类目标签技术提升智慧物流效率、准确性和成本控制。通过高效数据处理、实时监控和动态调整,AI技术显著优于传统方式。鸿蒙系统的分布式软总线技术和隐私保护机制为智慧物流提供了坚实基础。从仓储管理到运输监控再到配送优化,AI类目标签技术助力物流全流程智能化,提高客户满意度并降低成本。开发者可借助深度学习框架和鸿蒙系统特性,开发创新应用,推动物流行业智能化升级。
207 1
|
8月前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。

热门文章

最新文章

推荐镜像

更多
  • DNS