Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wash/validate a string to assign it to a componentname?

Tags:

delphi

I have a submenu that list departments. Behind this each department have an action who's name is assigned 'actPlan' + department.name.

Now I realize this was a bad idea because the name can contain any strange character in the world but the action.name cannot contain international characters. Obviously Delphi IDE itself call some method to validate if a string is a valid componentname. Anyone know more about this ?

I have also an idea to use

Action.name := 'actPlan' + department.departmentID;

instead. The advantage is that departmentID is a known format, 'xxxxx-x' (where x is 1-9), so I have only to replace '-' with for example underscore. The problem here is that those old actionnames are already persisted in a personal textfile. It will be exceptions if I suddenly change from using departments name to the ID.

I could of course eat the exception first time and then call a method that search replace that textfile with the right data and reload it.

So basically I search the most elegant and futureproof method to solve this :) I use D2007.

like image 406
Roland Bengtsson Avatar asked Dec 03 '22 07:12

Roland Bengtsson


1 Answers

Component names are validated using the IsValidIdent function from SysUtils, which simply checks whether the first character is alphabetic or an underscore and whether all subsequent characters are alphanumeric or an underscore.

To create a string that fits those rules, simply remove any characters that don't qualify, and then add a qualifying character if the result starts with a number.

That transformation might yield the same result for similar names. If that's not something you want, then you can add something unique to the end of the string, such as a checksum computed from the input string, or your department ID.

function MakeValidIdent(const s: string): string;
var
  len: Integer;
  x: Integer;
  c: Char;
begin
  SetLength(Result, Length(s));
  x := 0;
  for c in s do
    if c in ['A'..'Z', 'a'..'z', '0'..'9', '_'] then begin
      Inc(x);
      Result[x] := c;
    end;
  SetLength(Result, x);
  if x = 0 then
    Result := '_'
  else if Result[1] in ['0'..'9'] then
    Result := '_' + Result;
  // Optional uniqueness protection follows. Choose one.
  Result := Result + IntToStr(Checksum(s));
  Result := Result + GetDepartment(s).ID;
end;

In Delphi 2009 and later, replace the second two in operators with calls to the CharInSet function. (Unicode characters don't work well with Delphi sets.) In Delphi 8 and earlier, change the first in operator to a classic for loop and index into s.

like image 169
Rob Kennedy Avatar answered Dec 18 '22 15:12

Rob Kennedy