How to read the value of ParamStr parameter with different delimiters?

When you read ParamStr() , it divides spaces between each parameter. However, I saw many command line arguments that take a space between the parameter name and its paired value, and also take the equal sign = and even without a separator (just a prefix with the parameter name) or without a value.

Here are some examples of possible parameter strings:

 -name value /name value -name=value /name=value -namevalue /namevalue -name -nextname /name /nextname -name="value with spaces" /name="value with spaces" 

... etc..

What I would like to do are two things that are related to each other ... Check if the parameter name exists and read the parameter value. For instance...

 if ParamExists('ParamName') then SomeString:= ParamValue('ParamName') else SomeString:= 'SomeOtherString'; 

Is there anything in Delphi that can do this? If not, how do I do this? All that I find in the search just leads me to the same basic example:

 for i := 0 to ParamCount do ShowMessage(ParamStr(i)); 

It must also be case sensitive. I am looking for something especially, such as OSQL and similar command line tools, where "-s" may be different from "-S".

The problem is that if I use a space as a separator, I don’t know how to recognize its part of the previous parameter, because it separates them with spaces. How do I get around this?

I am sure that there is also a standard term for this, this is the general formatting of command line arguments. But I do not know how to read them correctly using only ParamStr . ParamStr seems to be ParamStr behind what is commonly used for.

To be clear, I don't have to support every example above - these are just the examples I saw before.

+4
source share
3 answers

ParamStr() (and therefore FindCmdLineSwitch() ) is not flexible enough to handle all the examples you cited. You will need to call the Win32 API GetCommandLine() function and analyze it manually.

+4
source

Ironically, only last night I wrote something for this, and a little back found that it raised-voted. Here is the class I just wrote encapsulating this:

 unit CmdLine; (* Command Line Parser by Jerry Dodge Class: TCmdLine - Parses out a command line into individual name/value pairs - Concatenates name/value pairs into a command line string - Property "ModuleFilename" for the current executable path - Property "OpenFilename" for the file to be opened, if any - Default property "Values" to read/write name/value pairs *) interface uses System.Classes, System.SysUtils; type TCmdLine = class(TObject) private FItems: TStringList; FModuleFilename: String; FOpenFilename: String; function GetAsString: String; procedure SetAsString(const Value: String); procedure SetModuleFilename(const Value: String); procedure SetOpenFilename(const Value: String); function GetValue(const Name: String): String; procedure SetValue(const Name, Value: String); function GetName(const Index: Integer): String; public constructor Create; destructor Destroy; override; function Count: Integer; function Exists(const N: String; const IgnoreCase: Boolean = False): Boolean; property ModuleFilename: String read FModuleFilename write SetModuleFilename; property OpenFilename: String read FOpenFilename write SetOpenFilename; property AsString: String read GetAsString write SetAsString; property Names[const Index: Integer]: String read GetName; property Values[const Name: String]: String read GetValue write SetValue; default; end; implementation { TCmdLine } constructor TCmdLine.Create; begin FItems:= TStringList.Create; end; destructor TCmdLine.Destroy; begin FItems.Free; inherited; end; function TCmdLine.Count: Integer; begin Result:= FItems.Count; end; function TCmdLine.Exists(const N: String; const IgnoreCase: Boolean = False): Boolean; var X: Integer; begin Result:= False; for X := 0 to FItems.Count-1 do begin if IgnoreCase then begin if SameText(N, FItems.Names[X]) then begin Result:= True; Break; end; end else begin if N = FItems.Names[X] then begin Result:= True; Break; end; end; end; end; procedure TCmdLine.SetModuleFilename(const Value: String); begin FModuleFilename:= Value; end; procedure TCmdLine.SetOpenFilename(const Value: String); begin FOpenFilename:= Value; end; function TCmdLine.GetValue(const Name: String): String; begin Result:= FItems.Values[Name]; end; procedure TCmdLine.SetValue(const Name, Value: String); begin FItems.Values[Name]:= Value; end; function TCmdLine.GetAsString: String; var X: Integer; Cmd: String; Val: String; begin Result:= '"'+FModuleFilename+'"'; if Trim(FOpenFilename) <> '' then Result:= Result + ' "'+FOpenFilename+'"'; for X := 0 to FItems.Count-1 do begin Cmd:= FItems.Names[X]; Val:= FItems.Values[Cmd]; Result:= Result + ' -'+Cmd; if Trim(Val) <> '' then begin Result:= Result + ' '; if Pos(' ', Val) > 0 then Result:= Result + '"'+Val+'"' else Result:= Result + Val; end; end; end; function TCmdLine.GetName(const Index: Integer): String; begin Result:= FItems.Names[Index]; end; procedure TCmdLine.SetAsString(const Value: String); var Str: String; Tmp: String; Cmd: String; Val: String; P: Integer; begin FItems.Clear; FModuleFilename:= ''; FOpenFilename:= ''; Str:= Trim(Value) + ' '; //Extract module filename P:= Pos('"', Str); if P = 1 then begin Delete(Str, 1, 1); P:= Pos('"', Str); Tmp:= Copy(Str, 1, P-1); Delete(Str, 1, P); FModuleFilename:= Tmp; end else begin P:= Pos(' ', Str); Tmp:= Copy(Str, 1, P-1); Delete(Str, 1, P); FModuleFilename:= Tmp; end; Str:= Trim(Str) + ' '; //Extract open filename P:= Pos('"', Str); if P = 1 then begin Delete(Str, 1, 1); P:= Pos('"', Str); Tmp:= Copy(Str, 1, P-1); Delete(Str, 1, P); FOpenFilename:= Tmp; end else begin P:= Pos('-', Str); if P < 1 then P:= Pos('/', 'Str'); if P < 1 then begin P:= Pos(' ', Str); Tmp:= Copy(Str, 1, P-1); Delete(Str, 1, P); FOpenFilename:= Tmp; end; end; Str:= Trim(Str) + ' '; //Extract remaining param switches/values while Length(Trim(Str)) > 0 do begin P:= Pos('-', Str); if P < 1 then P:= Pos('/', 'Str'); if P > 0 then begin Delete(Str, 1, 1); P:= Pos(' ', Str); Tmp:= Trim(Copy(Str, 1, P-1)); Delete(Str, 1, P); if Pos('"', Tmp) = 1 then begin Delete(Tmp, 1, 1); P:= Pos('"', Tmp); if P > 0 then Delete(Tmp, 1, 1); end; Cmd:= Tmp; Str:= Trim(Str) + ' '; if (Pos('-', Str) <> 1) and (Pos('/', Str) <> 1) then begin P:= Pos('"', Str); if P = 1 then begin Delete(Str, 1, 1); P:= Pos('"', Str); Tmp:= Copy(Str, 1, P-1); Delete(Str, 1, P); end else begin P:= Pos(' ', Str); Tmp:= Copy(Str, 1, P-1); Delete(Str, 1, P); end; Val:= Tmp; end else begin Val:= ''; end; if Val = '' then Val:= ' '; FItems.Values[Cmd]:= Val; end else begin Str:= ''; raise Exception.Create('Command line parameters malformed ('+Str+')'); end; Str:= Trim(Str) + ' '; end; end; end. 
0
source

I just rewrote my entire suggested answer to add some value to it, thanks for your comments:

 function TForm1.ParamExists(sParamName: String; bIgnoreCase: boolean; equalchar : string = '='): Boolean; begin if bIgnoreCase then Result := Pos(sParamName + equalChar, cmdLine) > 0 else Result := AnsiPos(sParamName + equalChar, cmdLine) > 0; end; function TForm1.ParamValue(sParamName : String; bIgnoreCase : boolean = false; equalchar : string = '='; delimiter : string = '"'): String; var I : Integer; scmdLine : String; begin Result := ''; scmdLine := cmdLine; if bIgnoreCase then I := Pos(sParamName, scmdLine) else I := AnsiPos(sParamName, scmdLine); inc(I, Length(sParamName + equalchar)); delete(scmdLine, 1, I-1); if pos(delimiter, scmdLine) = 1 then begin delete(scmdLine, 1, 1); Result := copy(scmdLine,1, pos(delimiter, scmdLine) -1); end else Result := copy(scmdLine,1, pos(' ', scmdLine)); end; 

Suppose these options are:

 project1.exe -name1 value1 /name2 value2 -name3=value3 /name4=value4 -name5value5 /name6value6 -name7 -name8 /name9 /name91 -name10="Value 10" /name11="Value 11" 

Example:

 ParamExists('-Name1', False, ' '); --> False ParamExists('-Name1', True, ' '); --> True, ignore case ParamExists('-name1', False, ' '); --> True ParamExists('-name1', False, '='); --> False there are no a = after -name1 parameter ParamExists('-name6', False, ''); --> True this parameter use the form -parameterValue 

ParameterValue example:

 ParamValue('-name1', false, ' '); --> value1 ParamValue('/name2', false, ' '); --> value2 ParamValue('-name3'); --> value3, using default values ParamValue('-name4'); --> value4, using default values ParamValue('-name5', false, ''); --> value5 ParamValue('/name6', false, ''); --> value6 

Note that the -name7, -name8, / name9, and / name91 options must be evaluated as ParamExists because no value is specified for them.

 ParamValue('-name10', false, '=', '"'); --> Value 10 same as: ParamValue('-name10'); --> Value 10 ParamValue('/name11'); --> Value 11 
-1
source

Source: https://habr.com/ru/post/1486355/


All Articles