Function TfrmProc.ChangeValue( pData : WideString; KeyVar: String; pIncr : Integer ) : WideString;
VAR X : Byte;
_lPosIni, _lPosEqual, _lPosSep : smallint;
_lStrBegin, _lStrEnd : WideString;
_lValue : Integer;
Begin
Result := pData;
if NOT (Pos(AnsiUpperCase(KeyVar), AnsiUpperCase(pData)) > 0) then
EXIT;
_lPosIni := Pos(AnsiUpperCase(KeyVar), AnsiUpperCase(pData))
_lPosEqual:=PosFrom( pData,'=', _lPosIni+Length(KeyVar)-1 );
// Search for sep - 'B' OR ;
for X := _lPosEqual to Length(pData) do
if (pData[X]=';') OR (pData[X]=' ') then Begin
_lPosSep := X;
Break;
end;
_lStrBegin:= SubStr( pData, 0, _lPosEqual);
_lValue := StrToInt( SubStr( pData, _lPosEqual+1, ((_lPosSep-1)-_lPosEqual)) );
_lValue := _lValue + pIncr;
_lStrEnd := SubStr( pData, _lPosSep+1 );
Result := format('%s%d;%s',[_lStrBegin,_lValue,_lStrEnd])
End;
function PosFrom(Text : WideString; search : Char; Position : Integer) : Integer;
var L, X : Integer;
begin
Result := 0;
L := Length(Text);
if (Position > L) or (Position < 1) then
Exit;
for X := Position to L do begin
if UpperCase(Text[X]) = String(Search) then Begin
Result := X;
Exit;
end
end;
end;
Refactorings
No refactoring yet !
X-Ray
February 21, 2009, February 21, 2009 17:46, permalink
this comment doesn't directly answer your question but here's how i do things like that.
i like to use TStringList's parsing. StringReplace hasn't been so fast but usually it doesn't matter much.
// not tested
var
sl:TStringList;
begin
sl:=TStringList.Create;
try
// i think Text property splits on space AND #13. if it doesn't, you can repl space with #13 too
sl.Text:=StringReplace(s, ';', #13, [rfReplaceAll]);
sl.Values[sTokenName]:='something';
Result:=sl.Values[sTokenName];
finally
sl.Free;
end;
end;
ahuser
February 22, 2009, February 22, 2009 11:00, permalink
This code is is based on your algorithm but it is optimized to not unnecessary convert strings and chars.
{$IFNDEF UNICODE} // pre Delphi 2009
type
UnicodeString = WideString;
{$ENDIF ~UNICODE}
function ChangeValue(const AData: UnicodeString; const AKeyVar: UnicodeString; AIncr: Integer): UnicodeString;
var
I: Integer;
lPosIni, lPosEqual, lPosSep: Integer;
lStrBegin, lStrEnd: UnicodeString;
lValue: Integer;
lDataLen: Integer;
Begin
{$IFDEF UNICODE}
lPosIni := Pos(AnsiUpperCase(AKeyVar), AnsiUpperCase(AData));
{$ELSE}
lPosIni := Pos(WideUpperCase(AKeyVar), WideUpperCase(AData));
{$ENDIF UNICODE}
if lPosIni = 0 then
begin
Result := AData;
Exit;
end;
lDataLen := Length(AData);
// Find equal symbol
lPosEqual := 0;
for I := lPosIni + Length(AKeyVar) to lDataLen do
begin
case AData[I] of
'=':
begin
lPosEqual := I;
Break;
end;
' ', ';':
Break; // no equal symbol for this KeyVar
end;
end;
// Search for sep - 'B' OR ;
if lPosEqual <> 0 then
begin
lPosSep := lDataLen + 1;
for I := lPosEqual + 1 to lDataLen do
begin
if (AData[I] = ';') or (AData[I] = ' ') then
begin
lPosSep := I;
Break;
end;
end;
lStrBegin := Copy(AData, 1, lPosEqual);
lValue := AIncr + StrToInt(Copy(AData, lPosEqual + 1, (lPosSep - 1) - lPosEqual));
lStrEnd := Copy(AData, lPosSep, MaxInt);
Result := Format('%s%d%s', [lStrBegin, lValue, lStrEnd])
end
else
Result := AData;
end;
Wouter van Nifterick
March 5, 2010, March 05, 2010 03:11, permalink
The program below outputs the following:
CONFIG;Ver=1.0;MENUSOUND=ON;DEFAULTSEC=3456;SHowDate=ON;DATE=
CONFIG;Ver=1.0;MENUSOUND=ON;DEFAULTSEC=3356;SHowDate=ON;DATE=
Note that the value of DEFAULTSEC has been decreased by 100.
program TestChangeValue;
{$APPTYPE CONSOLE}
uses Classes, SysUtils;
function ChangeValue(const AData: UnicodeString; const AKeyVar: UnicodeString; AIncr: Integer): UnicodeString;
begin
with TStringList.Create do
try
Delimiter := ';';
DelimitedText := AData;
Values[AKeyVar] := IntTostr(StrToIntDef(Values[AKeyVar],0)+AIncr);
Result := DelimitedText;
finally
Free;
end;
end;
// test it
const OldStr = 'CONFIG;Ver=1.0;MENUSOUND=ON;DEFAULTSEC=3456;SHowDate=ON;DATE=';
var NewStr:String;
begin
NewStr := ChangeValue(OldStr, 'DEFAULTSEC', -100);
WriteLn(OldStr,#13#10,NewStr);
ReadLn;
end.
It is something that we have to do lots of time, so it must be as simple and performante as possible.
I have this simple but horrible code.
The string/WideString here I have to change is like this:
‘CONFIG;Ver=1.0;MENUSOUND=ON;DEFAULTSEC=3456;SHowDate=ON;DATE=â€â€ ’;
Separator is Blanks or ‘;’, so must check for both.
I must be able to get the Vars Values and change them.