一个不错的命令行解析类_#include

 作者所考虑的语法是:

一个不错的命令行解析类_大小写不敏感_02CommandLine::=[<Key> [,<Key>一个不错的命令行解析类_分隔符_03]]
一个不错的命令行解析类_大小写不敏感_02<Key>::=<Delimeter>KeyName[<Separator><Value>]
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06<Value> ::= 一个不错的命令行解析类_分隔符_03{ KeyValue | <QuoteChar>Quoted Key Value<QuoteChar>} ][
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06<Delimeter>::= 一个不错的命令行解析类_分隔符_03{ - | / }
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06<Separator>::= 一个不错的命令行解析类_分隔符_03{ : }
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06<QuoteChar>::= 一个不错的命令行解析类_分隔符_03{ " }
一个不错的命令行解析类_大小写不敏感_02



一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02typedef CString CCmdLineParser_String ;
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02#include <map>
一个不错的命令行解析类_大小写不敏感_02using std::map;
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02class CCmdLineParser 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29public:
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    class CValsMap : public map<CCmdLineParser_String, CCmdLineParser_String> 一个不错的命令行解析类_分隔符_03{};//存储关键字--值对
一个不错的命令行解析类_分隔符_29    typedef CValsMap::const_iterator POSITION;//迭代器
一个不错的命令行解析类_分隔符_29public:
一个不错的命令行解析类_分隔符_29    CCmdLineParser(LPCTSTR sCmdLine = NULL, bool bCaseSensitive = false);//默认大小写不敏感
一个不错的命令行解析类_分隔符_29    virtual ~CCmdLineParser();
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    bool Parse(LPCTSTR sCmdLine);//解析命令行
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    LPCTSTR getCmdLine() const 一个不错的命令行解析类_分隔符_03{ return m_sCmdLine; }
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    void setCaseSensitive(bool bSensitive) 一个不错的命令行解析类_分隔符_03{ m_bCaseSensitive = bSensitive; }
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    bool getCaseSensitive() const 一个不错的命令行解析类_分隔符_03{ return m_bCaseSensitive; }
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    const CValsMap& getVals() const 一个不错的命令行解析类_分隔符_03{ return m_ValsMap; }
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    // Start iterating through keys and values
一个不错的命令行解析类_分隔符_29    POSITION getFirst() const;//第一个
一个不错的命令行解析类_分隔符_29    // Get next key-value pair, returns empty sKey if end reached
一个不错的命令行解析类_分隔符_29    POSITION getNext(POSITION& pos, CCmdLineParser_String& sKey, CCmdLineParser_String& sValue) const;//迭代器往后
一个不错的命令行解析类_分隔符_29    // just helper ;)
一个不错的命令行解析类_分隔符_29    bool isLast(POSITION& pos) const;//是否是最后一个
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    // TRUE if "Key" present in command line
一个不错的命令行解析类_分隔符_29    bool HasKey(LPCTSTR sKey) const;//是否包含指定关键字
一个不错的命令行解析类_分隔符_29    // Is "key" present in command line and have some value
一个不错的命令行解析类_分隔符_29    bool HasVal(LPCTSTR sKey) const;//是否包含指定值
一个不错的命令行解析类_分隔符_29    // Returns value if value was found or NULL otherwise
一个不错的命令行解析类_分隔符_29    LPCTSTR GetVal(LPCTSTR sKey) const;//获取值
一个不错的命令行解析类_分隔符_29    // Returns true if value was found
一个不错的命令行解析类_分隔符_29    bool GetVal(LPCTSTR sKey, CCmdLineParser_String& sValue) const;
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29private:
一个不错的命令行解析类_分隔符_29    CValsMap::const_iterator findKey(LPCTSTR sKey) const;//查找指定关键字
一个不错的命令行解析类_分隔符_29private:
一个不错的命令行解析类_分隔符_29    CCmdLineParser_String m_sCmdLine;
一个不错的命令行解析类_分隔符_29    CValsMap    m_ValsMap;
一个不错的命令行解析类_分隔符_29    bool m_bCaseSensitive;
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    static const TCHAR m_sDelimeters[];
一个不错的命令行解析类_分隔符_29    static const TCHAR m_sValueSep[];
一个不错的命令行解析类_分隔符_29    static const TCHAR m_sQuotes[];
一个不错的命令行解析类_分隔符_81};
一个不错的命令行解析类_大小写不敏感_02

 

一个不错的命令行解析类_大小写不敏感_02const TCHAR CCmdLineParser::m_sDelimeters[] = _T("-/");//键的起始符
一个不错的命令行解析类_大小写不敏感_02const TCHAR CCmdLineParser::m_sQuotes[] = _T("\"");    // Can be _T("\"\'"),  for instance
一个不错的命令行解析类_大小写不敏感_02const TCHAR CCmdLineParser::m_sValueSep[] = _T(" :"); // Space MUST be in set 键值分隔符
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06/**///////////////////////////////////////////////////////////////////////
一个不错的命令行解析类_大小写不敏感_02// Construction/Destruction
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06/**///////////////////////////////////////////////////////////////////////
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02CCmdLineParser::CCmdLineParser(LPCTSTR sCmdLine, bool bCaseSensitive)
一个不错的命令行解析类_大小写不敏感_02: m_bCaseSensitive(bCaseSensitive)
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    if(sCmdLine) 
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29        Parse(sCmdLine);
一个不错的命令行解析类_分隔符_103    }
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02CCmdLineParser::~CCmdLineParser()
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    m_ValsMap.clear();
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02bool CCmdLineParser::Parse(LPCTSTR sCmdLine) 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    if(!sCmdLine) return false;
一个不错的命令行解析类_分隔符_29    
一个不错的命令行解析类_分隔符_29    m_sCmdLine = sCmdLine;
一个不错的命令行解析类_分隔符_29    m_ValsMap.clear();
一个不错的命令行解析类_分隔符_29    const CCmdLineParser_String sEmpty;
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    int nArgs = 0;
一个不错的命令行解析类_分隔符_29    LPCTSTR sCurrent = sCmdLine;
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    while(true) 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29        // /Key:"arg"
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31        if(_tcslen(sCurrent) == 0) 一个不错的命令行解析类_分隔符_03{ break; } // No data left
一个不错的命令行解析类_分隔符_29        LPCTSTR sArg = _tcspbrk(sCurrent, m_sDelimeters);
一个不错的命令行解析类_分隔符_29        if(!sArg) break; // No delimeters found
一个不错的命令行解析类_分隔符_29        sArg =  _tcsinc(sArg);
一个不错的命令行解析类_分隔符_29        // Key:"arg"
一个不错的命令行解析类_分隔符_29        if(_tcslen(sArg) == 0) break; // String ends with delimeter
一个不错的命令行解析类_分隔符_29        LPCTSTR sVal = _tcspbrk(sArg, m_sValueSep);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31        if(sVal == NULL) 一个不错的命令行解析类_分隔符_03{ //Key ends command line
一个不错的命令行解析类_分隔符_29            CCmdLineParser_String csKey(sArg);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            if(!m_bCaseSensitive) 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29                csKey.MakeLower();
一个不错的命令行解析类_分隔符_103            }
一个不错的命令行解析类_分隔符_29            m_ValsMap.insert(CValsMap::value_type(csKey, sEmpty));
一个不错的命令行解析类_分隔符_29            break;
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31        } else if(sVal[0] == _T(' ') || _tcslen(sVal) == 1 ) 一个不错的命令行解析类_分隔符_03{ // Key with no value or cmdline ends with /Key:
一个不错的命令行解析类_分隔符_29            CCmdLineParser_String csKey(sArg, sVal - sArg);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            if(!csKey.IsEmpty()) 一个不错的命令行解析类_分隔符_03{ // Prevent /: case
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31                if(!m_bCaseSensitive) 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29                    csKey.MakeLower();
一个不错的命令行解析类_分隔符_103                }
一个不错的命令行解析类_分隔符_29                m_ValsMap.insert(CValsMap::value_type(csKey, sEmpty));
一个不错的命令行解析类_分隔符_103            }
一个不错的命令行解析类_分隔符_29            sCurrent = _tcsinc(sVal);
一个不错的命令行解析类_分隔符_29            continue;
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31        } else 一个不错的命令行解析类_分隔符_03{ // Key with value
一个不错的命令行解析类_分隔符_29            CCmdLineParser_String csKey(sArg, sVal - sArg);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            if(!m_bCaseSensitive) 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29                csKey.MakeLower();
一个不错的命令行解析类_分隔符_103            }
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29            sVal = _tcsinc(sVal);
一个不错的命令行解析类_分隔符_29            // "arg"
一个不错的命令行解析类_分隔符_29            LPCTSTR sQuote = _tcspbrk(sVal, m_sQuotes), sEndQuote(NULL);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            if(sQuote == sVal) 一个不错的命令行解析类_分隔符_03{ // Quoted String
一个不错的命令行解析类_分隔符_29                sQuote = _tcsinc(sVal);
一个不错的命令行解析类_分隔符_29                sEndQuote = _tcspbrk(sQuote, m_sQuotes);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            } else 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29                sQuote = sVal;
一个不错的命令行解析类_分隔符_29                sEndQuote = _tcschr(sQuote, _T(' '));
一个不错的命令行解析类_分隔符_103            }
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            if(sEndQuote == NULL) 一个不错的命令行解析类_分隔符_03{ // No end quotes or terminating space, take rest of string
一个不错的命令行解析类_分隔符_29                CCmdLineParser_String csVal(sQuote);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31                if(!csKey.IsEmpty()) 一个不错的命令行解析类_分隔符_03{ // Prevent /:val case
一个不错的命令行解析类_分隔符_29                    m_ValsMap.insert(CValsMap::value_type(csKey, csVal));//保存
一个不错的命令行解析类_分隔符_103                }
一个不错的命令行解析类_分隔符_29                break;
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31            } else 一个不错的命令行解析类_分隔符_03{ // End quote or space present
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31                if(!csKey.IsEmpty()) 一个不错的命令行解析类_分隔符_03{    // Prevent /:"val" case
一个不错的命令行解析类_分隔符_29                    CCmdLineParser_String csVal(sQuote, sEndQuote - sQuote);
一个不错的命令行解析类_分隔符_29                    m_ValsMap.insert(CValsMap::value_type(csKey, csVal));
一个不错的命令行解析类_分隔符_103                }
一个不错的命令行解析类_分隔符_29                sCurrent = _tcsinc(sEndQuote);
一个不错的命令行解析类_分隔符_29                continue;
一个不错的命令行解析类_分隔符_103            }
一个不错的命令行解析类_分隔符_103        }
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_103    }
一个不错的命令行解析类_分隔符_29    
一个不错的命令行解析类_分隔符_29    return (nArgs > 0);
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02CCmdLineParser::CValsMap::const_iterator CCmdLineParser::findKey(LPCTSTR sKey) const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    CCmdLineParser_String s(sKey);
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    if(!m_bCaseSensitive) 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29        s.MakeLower();
一个不错的命令行解析类_分隔符_103    }
一个不错的命令行解析类_分隔符_29    return m_ValsMap.find(s);
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02// TRUE if "Key" present in command line
一个不错的命令行解析类_大小写不敏感_02bool CCmdLineParser::HasKey(LPCTSTR sKey) const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    CValsMap::const_iterator it = findKey(sKey);
一个不错的命令行解析类_分隔符_29    if(it == m_ValsMap.end()) return false;
一个不错的命令行解析类_分隔符_29    return true;
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02// Is "key" present in command line and have some value
一个不错的命令行解析类_大小写不敏感_02bool CCmdLineParser::HasVal(LPCTSTR sKey) const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    CValsMap::const_iterator it = findKey(sKey);
一个不错的命令行解析类_分隔符_29    if(it == m_ValsMap.end()) return false;
一个不错的命令行解析类_分隔符_29    if(it->second.IsEmpty()) return false;
一个不错的命令行解析类_分隔符_29    return true;
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02// Returns value if value was found or NULL otherwise
一个不错的命令行解析类_大小写不敏感_02LPCTSTR CCmdLineParser::GetVal(LPCTSTR sKey) const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    CValsMap::const_iterator it = findKey(sKey);
一个不错的命令行解析类_分隔符_29    if(it == m_ValsMap.end()) return false;
一个不错的命令行解析类_分隔符_29    return LPCTSTR(it->second);
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02// Returns true if value was found
一个不错的命令行解析类_大小写不敏感_02bool CCmdLineParser::GetVal(LPCTSTR sKey, CCmdLineParser_String& sValue) const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    CValsMap::const_iterator it = findKey(sKey);
一个不错的命令行解析类_分隔符_29    if(it == m_ValsMap.end()) return false;
一个不错的命令行解析类_分隔符_29    sValue = it->second;
一个不错的命令行解析类_分隔符_29    return true;
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02CCmdLineParser::POSITION CCmdLineParser::getFirst() const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    return m_ValsMap.begin();
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02CCmdLineParser::POSITION CCmdLineParser::getNext(POSITION& pos, CCmdLineParser_String& sKey, CCmdLineParser_String& sValue) const 
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    if(isLast(pos)) 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29        sKey.Empty();
一个不错的命令行解析类_分隔符_29        return pos;
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    } else 一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29        sKey = pos->first;
一个不错的命令行解析类_分隔符_29        sValue = pos->second;
一个不错的命令行解析类_分隔符_29        pos ++;
一个不错的命令行解析类_分隔符_29        return pos;
一个不错的命令行解析类_分隔符_103    }
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02// just helper ;)
一个不错的命令行解析类_大小写不敏感_02bool CCmdLineParser::isLast(POSITION& pos) const
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    return (pos == m_ValsMap.end());
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02

 

一个不错的命令行解析类_大小写不敏感_02#include "stdafx.h"
一个不错的命令行解析类_大小写不敏感_02#include "cmdlineparser.h"
一个不错的命令行解析类_大小写不敏感_02
一个不错的命令行解析类_大小写不敏感_02int main(int argc, char* argv[])
一个不错的命令行解析类_分隔符_05一个不错的命令行解析类_命令行_06一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29    CCmdLineParser parser(_T("/Key1 /Key2: -Key3:Val3 -Key4:\"Val 4-with/spaces/and-delimeters\" /Key5:Val5"));
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    ASSERT(parser.HasKey(_T("Key1")) == true);
一个不错的命令行解析类_分隔符_29    ASSERT(parser.HasKey(_T("Key10")) == false);
一个不错的命令行解析类_分隔符_29    ASSERT(parser.HasVal(_T("Key2")) == false);
一个不错的命令行解析类_分隔符_29    ASSERT(parser.HasKey(_T("Key5"))==true);
一个不错的命令行解析类_分隔符_29    _tprintf(_T("==================== Test Parser ====================\n"));
一个不错的命令行解析类_分隔符_29    _tprintf(_T("Command line: [%s]\n"), parser.getCmdLine());//获取命令行参数
一个不错的命令行解析类_分隔符_29    _tprintf(_T("Key1 has value: [%s]\n"), parser.GetVal(_T("Key1")));// -> []; //(empty string)
一个不错的命令行解析类_分隔符_29    _tprintf(_T("Key2 has value: [%s]\n"), parser.GetVal(_T("Key2")));// -> []; 
一个不错的命令行解析类_分隔符_29    _tprintf(_T("Key3 has value: [%s]\n"), parser.GetVal(_T("Key3")));// -> [Val3];
一个不错的命令行解析类_分隔符_29    _tprintf(_T("Key4 has value: [%s]\n"), parser.GetVal(_T("Key4")));// -> [Val 4-with/spaces/and-delimeters];
一个不错的命令行解析类_分隔符_29    _tprintf(_T("Key5 has value: [%s]\n"), parser.GetVal(_T("Key5")));// -> []; //(empty string)
一个不错的命令行解析类_分隔符_29
一个不错的命令行解析类_分隔符_29    _tprintf(_T("\n================= Real Command Line =================\n"));
一个不错的命令行解析类_分隔符_29    CCmdLineParser realParser(::GetCommandLine());
一个不错的命令行解析类_分隔符_29    CCmdLineParser::POSITION pos = realParser.getFirst();    
一个不错的命令行解析类_分隔符_29    CString sKey, sVal;
一个不错的命令行解析类_分隔符_29    while(!realParser.isLast(pos)) 
一个不错的命令行解析类_命令行_30一个不错的命令行解析类_#include_31    一个不错的命令行解析类_分隔符_03{
一个不错的命令行解析类_分隔符_29        realParser.getNext(pos, sKey, sVal);
一个不错的命令行解析类_分隔符_29        _tprintf(_T("Key: [%s], Val: [%s]\n"), sKey, sVal);
一个不错的命令行解析类_分隔符_103    }
一个不错的命令行解析类_分隔符_29    system("pause");
一个不错的命令行解析类_分隔符_29    return 0;
一个不错的命令行解析类_分隔符_81}
一个不错的命令行解析类_大小写不敏感_02