tags:

views:

391

answers:

2

Is it possible to pass a string as a TSysCharSet variable?

This does not compile of course:

var
  AValidChars: SysUtils.TSysCharSet;
  AResult: string;
begin
  // Edit1.Text can contain 0..9 or a..z
  AValidChars := SysUtils.TSysCharSet( [Edit1.Text] );
end;

Thanks, Bill

+5  A: 

No, it is not possible to simply pass a string as a TSysCharSet.

What you can do however is to create a TSysCharSet which contains all the chars in the string. This code would do this:

var
  AValidChars: SysUtils.TSysCharSet;
  s: AnsiString;
  i: integer;
begin
  // Edit1.Text can contain 0..9 or a..z
  AValidChars := [];
  s := Edit1.Text;
  for i := 1 to Length(s) do
    Include(AValidChars, s[i]);
end;

If you are not using an earlier Delphi version you could also make use of "for ... in" instead of the loop above:

var
  AValidChars: SysUtils.TSysCharSet;
  c: AnsiChar;
begin
  // Edit1.Text can contain 0..9 or a..z
  AValidChars := [];
  for c in Edit1.Text do
    Include(AValidChars, c);
end;

Note that in both code snippets AnsiString / AnsiChar is used, as this technique will not work with WideString or the Unicode string type introduced with Delphi 2009.

Many thanks to Craig Stuntz, Ken White and Rob Kennedy for their very valuable comments, I have edited this answer to address all of their points.

mghie
Unfair! <g> I was typing the Include statement in my version of the *exact* same code! :-)
Ken White
This would be a good case for using for .. in instead of for .. to
Craig Stuntz
@Craig: Thanks, answer edited to reflect this.
mghie
I'm not sure that for..in was the best here. TSysCharSet was around before for..in existed, IIRC, and therefore this code wouldn't work in those versions of Delphi, whereas for..to would.
Ken White
If you're using a version of Delphi where it doesn't work, then don't use it. If you're using a version of Delphi where it does work, then use it. IMHO.
Craig Stuntz
So in other words, the answer to Bill's question is no. You have to construct a set from the string. Also, might want to note that TSysCharSet doesn't support Unicode, so you should use AnsiChar and AnsiString in this code.
Rob Kennedy
Thanks to all of you for your helpful comments, I have edited the answer accordingly.
mghie
A: 

If in your Edit1.Text you have the string:

'0..9'

Then the following code should help you:

var 
  AValidChars: SysUtils.TSysCharSet;
  StartChar, EndChar: char;
  c: char;
begin
  StartChar := Edit1.Text[1]; // some validation should be done
  EndChar := Edit1.Text[4];
  AValidChars := [];
  for c := StartChar to EndChar do
    Include(AValidChars, c);
end;

A Delphi/Pascal parser can be used to validate the input.

Update:

More elaborated function supporting set constructors:

function StrToSysCharSet(const S: string): TSysCharSet;
var
  Elements: TStringList;
  CurrentElement: string;
  StartChar, EndChar: char;
  c: char;
  i: Integer;
  p: Integer;
  function ReadChar: Char;
  begin
    Result := CurrentElement[p];
    Inc(p);
  end;
  function NextIsDotDot: Boolean;
  begin
    Result := '..' = Copy(CurrentElement, p, 2);
  end;
begin
  Elements := TStringList.Create;
  try
    Elements.CommaText := S;
    Result := [];
    for i := 0 to Elements.Count - 1 do
    begin
      CurrentElement := Trim(Elements[i]);
      p := 1;
      StartChar := ReadChar;
      if NextIsDotDot then
      begin
        Inc(p, 2);
        EndChar := ReadChar;
        for c := StartChar to EndChar do
          Include(Result, c);
      end
      else
        Include(Result, StartChar);
    end;
  finally
    Elements.Free;
  end;
end;

It can be used like this:

S := '0..9, a..z';
AValidChars := StrToSysCharSet(S);

or

S := '0..9 and a..z';
AValidChars := StrToSysCharSet(AnsiReplaceText(S, ' and ', ', '));

Adapting to support

S := '''0''..''9'' and ''a''..''z'''

is simple.

Tiago Moraes
The OP specifically said in his comment '0'..'9' and 'a'..'z'. How do you do that with your code above? You can't. mghie and Craig gave the right answer in their combined post above.
Ken White
My code was just to give the idea, using a more elaborated parser would allow more possibilities. See the updated function.
Tiago Moraes