Convert string to set with ranges

Hi All

I need to convert a string to a set, but in that string I want to be able to specify sub ranges.

eg.

program Testit;

type
  TMyEnum = (a,b,c,d,e,f,g,h,i,j);
  TMySet = set of TMyEnum;

function StringToMySet(const value : string) : TMySet;
begin
//what to do here
end;

begin
var myset :=  StringToMySet('a-d,f, g-i');

end.

Any suggestions on how to achieve this?

Off the top of my head, I would look at converting the subranges to its list ( eg ‘b-d’ to ‘b, c, d’ ) then use the SetSetProp function in TypInfo.

Regards
Graeme

Then again it is probably just as easy to scan the string, adding elements to the resultant set as you go along.

It’s the conversion of the subranges which had me stumped for a bit - I have something working but it seems a bit ugly. Time to write some unit tests to break it!

function StringToCompilerVersions(const value : string) : TCompilerVersions;
var
  entries : TArray<string>;
  compilerVersion : TCompilerVersion;
  range : TArray<string>;
  lowVersion, highVersion : TCompilerVersion;
begin
  result := [];
  entries := SplitString(value, ',');
  for var entry in entries do
  begin
    //check for range
    if entry.Contains('-') then
    begin
      range := SplitString(entry,'-');
      Assert(length(range) = 2);
      lowVersion := StringToCompilerVersion(Trim(range[0]));
      if lowVersion = TCompilerVersion.UnknownVersion then
        raise EArgumentOutOfRangeException.Create('Invalid Compiler version : ' + range[0]);
      highVersion := StringToCompilerVersion(Trim(range[1]));
      if highVersion = TCompilerVersion.UnknownVersion then
        raise EArgumentOutOfRangeException.Create('Invalid Compiler version : ' + range[1]);

      for var version : TCompilerVersion := lowVersion to highVersion do
        Include(result, version);    
    end
    else
    begin
      compilerVersion := StringToCompilerVersion(Trim(entry));
      Include(result, compilerVersion);
    end;   
  end;
end;

The only problem I can see is handling the case where the range includes values already in the string and when the ranges like f-b (equivalent to b-f.

Yeah good catch, I guess I need to check whether the low > high values in the range and swap them if so.

If the range includes values already in the string it’s no big deal as calling Include will do nothing in that case.

This is for a quick n dirty command line utility (generate projects for multiple compiler versions from a template project) so it doesn’t need to be bullet proof, just good enough :wink:

I had a go to try to take a functional approach … along the lines of applying functions into data structures.

My idea was : Given string → array of strings → tuples with ordered entries → predicate on inclusion of enums.

I wouldn’t say it’s great, but maybe it’s not completely awful.
I changed array to list, and leaked it, just to make it look and add nicer.
Just trying to convey an idea before my brain zonked out for the night.

IMO, the lhs is something we should be able to do … and the rhs should be in a library or the language.

I want to look into this Repo … but to try this much out myself first : GitHub - gbegreg/MapReduce: MapReduce with Delphi

This code : GitHub - pmcgee69/Enum-to-Set: A sketch - aiming to try functional ideas.

It occurred to me that you can also allow ‘c-’ and ‘-e’ … with two extra lines:

         if (length(s) = 2) and ( s[2]='-' )  then exit ( result.create( s[1], 'z' ) );
         if (length(s) = 2) and ( s[1]='-' )  then exit ( result.create( 'a' , s[1]) );