随笔-341  评论-2670  文章-0  trackbacks-0
    当我们的程序需要运行在命令行环境下的时候,分解复杂的命令行参数往往成为一件不难但又麻烦的事情。我们经常发现.net的开发工具的命令行格式都是"/parameterA:valueA /parameterB:valueB"。如果我们希望使用这种格式的命令行参数的话,如何分析就成为我们需要解决的一个问题。

    我们可以通过WinMain或者GetCommandLine()来获得一个unicode格式的命令行参数。这个命令行参数是没有被分析过的,一个完整的字符串。首先,我们使用空格分解字符串,不过在遇到双引号的时候,我们忽略空格一直到遇到另一个双引号为止。所以下面的命令行参数:
"e:\Coding\VL++\Tools\KfpCompiler\Debug\KfpCompiler.exe" /library:"C:\Kernel FP\Library\" /output:"C:\Kernel FP\Output\" /code:"C:\Kernel FP\Game\Project.kproj" /print-error /print-report
    将会被分解成6行:
1 "e:\Coding\VL++\Tools\KfpCompiler\Debug\KfpCompiler.exe"
2 /library:"C:\Kernel FP\Library\"
3 /output:"C:\Kernel FP\Output\"
4 /code:"C:\Kernel FP\Game\Project.kproj"
5 /print-error
6 /print-report

    对于每一行的命令,我们可以总结出以下几种格式:
    1、值
    2、/参数
    3、/参数:值
    我们可以规定,如果值的第一个字符和最后一个字符都是双引号的话,那么忽略这两个双引号。我使用Vczh GUI写了一个win32程序显示命令行分析的结果,代码和截图如下:

    首先是程序的代码。这个程序阅读命令行参数之后,将分析结果显示在一个文本框上:
 1 #include "..\..\..\Library\Windows\VL_WinGUI.h"
 2 
 3 using namespace vl;
 4 using namespace vl::windows;
 5 using namespace vl::windows::placement;
 6 
 7 class MainForm : public VL_WinForm
 8 {
 9 protected:
10     VL_WinEdit*            edtCommandLines;
11 
12     void InitControls()
13     {
14         edtCommandLines=new VL_WinEdit(this,true);
15         edtCommandLines->SetVScroll(true);
16         edtCommandLines->SetHScroll(true);
17 
18         ApplyPlacement(
19             pControl(edtCommandLines,10)
20             );
21 
22         this->OnShow.Bind(this,&MainForm::MainForm_OnShow);
23     }
24 
25     void MainForm_OnShow(VL_Base* Sender)
26     {
27         VL_WinParameters* Parameters=GetApplication()->GetParameters();
28         Parameters->Parse(L'/',L':');
29         VUnicodeString Output;
30 
31         Output+=L"Command   : ["+Parameters->GetCommandLineString()+L"]\r\n";
32         for(VInt i=0;i<Parameters->GetCount();i++)
33         {
34             Output+=L"Parameter : ["+Parameters->GetParameter(i)+L"]\r\n";
35             Output+=L"Value     : ["+Parameters->GetValue(i)+L"]\r\n";
36         }
37         edtCommandLines->SetText(Output);
38     }
39 
40 public:
41     MainForm():VL_WinForm(true)
42     {
43         SetClientWidth(400);
44         SetClientHeight(300);
45         SetBorder(vwfbSingle);
46         SetText(L"Command Lines");
47         InitControls();
48         MoveCenter();
49     }
50 };
51 
52 void main()
53 {
54     (new MainForm)->Show();
55     GetApplication()->Run();
56 }

    然后是运行结果:

    程序中用到的VL_WinParameters类的代码如下:

    头文件:
 1         class VL_WinParameters : public VL_Base
 2         {
 3         protected:
 4             class CommandPair
 5             {
 6             public:
 7                 typedef VL_List<CommandPair , false>        List;
 8 
 9                 VUnicodeString        Parameter;
10                 VUnicodeString        Value;
11             };
12 
13             VUnicodeString            FString;
14             CommandPair::List        FCommands;
15             VWChar                    FParameterChar;
16             VWChar                    FValueChar;
17             VBool                    FParsed;
18         public:
19             VL_WinParameters(VUnicodeString Command);
20             ~VL_WinParameters();
21 
22             VUnicodeString            GetCommandLineString();
23             VInt                    GetCount();
24             VUnicodeString            GetParameter(VInt Index);
25             VUnicodeString            GetValue(VInt Index);
26             VBool                    IsParsed();
27             void                    Parse(VWChar ParameterChar , VWChar ValueChar);
28         };

    实现文件:
  1         VL_WinParameters::VL_WinParameters(VUnicodeString Command)
  2         {
  3             FString=Command;
  4             FParsed=false;
  5             FParameterChar=L'\0';
  6             FValueChar=L'\0';
  7         }
  8 
  9         VL_WinParameters::~VL_WinParameters()
 10         {
 11         }
 12 
 13         VUnicodeString VL_WinParameters::GetCommandLineString()
 14         {
 15             return FString;
 16         }
 17 
 18         VInt VL_WinParameters::GetCount()
 19         {
 20             return FCommands.GetCount();
 21         }
 22 
 23         VUnicodeString VL_WinParameters::GetParameter(VInt Index)
 24         {
 25             return FCommands[Index].Parameter;
 26         }
 27 
 28         VUnicodeString VL_WinParameters::GetValue(VInt Index)
 29         {
 30             return FCommands[Index].Value;
 31         }
 32 
 33         VBool VL_WinParameters::IsParsed()
 34         {
 35             return FParsed;
 36         }
 37 
 38         void VL_WinParameters::Parse(VWChar ParameterChar , VWChar ValueChar)
 39         {
 40             if(!ParameterChar || !ValueChar)return;
 41             if(FParameterChar!=ParameterChar || FValueChar!=ValueChar)
 42             {
 43                 FParameterChar=ParameterChar;
 44                 FValueChar=ValueChar;
 45 
 46                 FCommands.Clear();
 47                 VL_List<VUnicodeString , false> CommandStrings;
 48                 {
 49                     PCWChar Buffer=FString.Buffer();
 50                     VUnicodeString CurrentCommand;
 51                     VBool InString=false;
 52 
 53                     while(true)
 54                     {
 55                         if(InString)
 56                         {
 57                             switch(*Buffer)
 58                             {
 59                             case L'\0':
 60                                 InString=false;
 61                                 if(CurrentCommand!=L"")
 62                                 {
 63                                     CommandStrings.Add(CurrentCommand);
 64                                     CurrentCommand=L"";
 65                                 }
 66                                 break;
 67                             case L'\"':
 68                                 InString=false;
 69                             default:
 70                                 CurrentCommand+=*Buffer;
 71                             }
 72                         }
 73                         else
 74                         {
 75                             switch(*Buffer)
 76                             {
 77                             case L' ':case L'\0':
 78                                 if(CurrentCommand!=L"")
 79                                 {
 80                                     CommandStrings.Add(CurrentCommand);
 81                                     CurrentCommand=L"";
 82                                 }
 83                                 break;
 84                             case L'\"':
 85                                 InString=true;
 86                             default:
 87                                 CurrentCommand+=*Buffer;
 88                             }
 89                         }
 90                         if(*Buffer)
 91                         {
 92                             Buffer++;
 93                         }
 94                         else
 95                         {
 96                             break;
 97                         }
 98                     }
 99                 }
100                 for(VInt i=0;i<CommandStrings.GetCount();i++)
101                 {
102                     CommandPair Pair;
103                     PCWChar Buffer=CommandStrings[i].Buffer();
104                     if(*Buffer==FParameterChar)
105                     {
106                         Buffer++;
107                         while(true)
108                         {
109                             if(*Buffer)
110                             {
111                                 if(*Buffer==FValueChar)
112                                 {
113                                     Buffer++;
114                                     break;
115                                 }
116                                 else
117                                 {
118                                     Pair.Parameter+=*Buffer;
119                                     Buffer++;
120                                 }
121                             }
122                             else
123                             {
124                                 break;
125                             }
126                         }
127                     }
128                     if(*Buffer)
129                     {
130                         Pair.Value=Buffer;
131                         if(Pair.Value.Length()>=2 && Pair.Value.GetChar(0)==L'\"' && Pair.Value.GetChar(Pair.Value.Length()-1)==L'\"')
132                         {
133                             Pair.Value=Pair.Value.SubString(1,Pair.Value.Length()-2);
134                         }
135                     }
136                     FCommands.Add(Pair);
137                 }
138                 FParsed=true;
139             }
140         }
posted on 2008-12-24 01:13 陈梓瀚(vczh) 阅读(2147) 评论(2)  编辑 收藏 引用 所属分类: C++

评论:
# re: 分解复杂的命令行参数 2008-12-24 04:33 | amuro1987218
这个脚本语言准备跨平台么
win32的话用CommandLineToArgvW可以分割出参数  回复  更多评论
  
# re: 分解复杂的命令行参数 2008-12-24 04:35 | amuro1987218
似乎刚才理解失误 是在阐述制定的规则是把 闪了  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理