Comma-seperated sub string extract

I have a string containing comma-seperated values:

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

i.e. 20 values with commas seprating them (18 commas)

This string we will call MainString

I want a function will the following call

ExtractSubString(MainString, Start, Finish): string
where
 MainString is the string above
 Start is the first value to extract
 Finish is the last value to extract

ExtractSubString returns a string containing the substring

For example, I call ExtractSubString with the following parameters:

MainString,1,20
the returned substring looks like this:
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

or
MainString,5,20
the returned substring looks like this:
5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

or

MainString,5,15
the returned substring looks like this:
5,6,7,8,9,10,11,12,13,14,15

or

MainString,19,20
the returned substring looks like this:
19,20

i.e. I want to keep the commas intact

A function that does these three examples perfectly wins the points. It must also be fast. i don't need to know the actul values at any point so you can keep the whole thing as strings.

Cheers

Ian

iwatkinsAsked:
Who is Participating?
 
Ronald BusterConnect With a Mentor OwnerCommented:
Hi,

Here the solution for your problem, tested it on your 3 examples and it worked.

Enjoy

Regards,

Cono


<---CUT HERE----->

function ExtractSubString(Value : String; pos1,pos2 : integer ) : string;
var s1,s2 : string;
begin
  Result := '';

  s1 := Trim(Value);
  while pos(',',s1) > 0 do
    begin
      s2 := copy(s1,1,pos(',',s1)-1);
      if (StrToInt(s2) >= pos1) and (StrToInt(s2) <= pos2) then
        begin
          Result := Result + s2 + ',';
        end;
      delete(s1,1,pos(',',s1));
    end;

  if (StrToInt(s1) >= pos1) and (StrToInt(s1) <= pos2) then
    begin
      Result := Result + s1;
    end;
end;

<---CUT HERE----->
0
 
iwatkinsAuthor Commented:
Adjusted points to 400
0
 
heathprovostCommented:
Here is my version

function ExtractSubString(MainString: String; Start, Finish: integer): string;
var
  TempString: String;
  CommaCount: integer;
  StartPos, EndPos: integer;
  StringLength: integer;
begin
  TempString := ',' + MainString + ',';
  StringLength := Length(TempString);
  CommaCount := 0;
  StartPos := 1;
  Repeat
    if TempString[StartPos] = ',' then Inc(CommaCount);
    Inc(StartPos);
    if StartPos = StringLength then
    begin
      Result := 'ERROR';
      Exit;
    end;
  Until CommaCount = Start;
  CommaCount := 0;
  EndPos := StartPos + 1;
  Repeat
    if TempString[EndPos] = ',' then Inc(CommaCount);
    Inc(EndPos);
    if EndPos = StringLength then
    begin
      Result := 'ERROR';
      Exit;
    end;
  Until CommaCount = Finish - Start + 1;
  Result := Copy(TempString, StartPos, EndPos - StartPos - 1);
end;

Heath
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

 
heathprovostCommented:
Condensed a bit


function ExtractSubString(MainString: String; Start, Finish: integer): string;
var
  TempString: String;
  CommaCount: integer;
  StartPos, EndPos: integer;
  StringLength: integer;
begin
  Result := 'ERROR';
  TempString := ',' + MainString + ',';
  StringLength := Length(TempString);
  CommaCount := 0;
  StartPos := 1;
  Repeat
    if TempString[StartPos] = ',' then Inc(CommaCount);
    Inc(StartPos);
    if StartPos = StringLength then
      Exit;
  Until CommaCount = Start;
  CommaCount := 0;
  EndPos := StartPos + 1;
  Repeat
    if TempString[EndPos] = ',' then Inc(CommaCount);
    Inc(EndPos);
    if EndPos = StringLength then
      Exit;
    end;
  Until CommaCount = Finish - Start + 1;
  Result := Copy(TempString, StartPos, EndPos - StartPos - 1);
end;


Heath
0
 
heathprovostCommented:
The best I can do.....(Fixed bug in error code and condensed a bit more)

function ExtractSubString(MainString: String; Start, Finish: integer): string;
var
  TempString: String;
  CommaCount: integer;
  StartPos, EndPos: integer;
  StringLength: integer;
begin
  Result := 'ERROR';
  TempString := ',' + MainString + ',';
  StringLength := Length(TempString);
  CommaCount := 0;
  StartPos := 1;
  Repeat
    if StartPos > StringLength then Exit;
    if TempString[StartPos] = ',' then Inc(CommaCount);
    Inc(StartPos);
  Until CommaCount = Start;
  CommaCount := 0;
  EndPos := StartPos + 1;
  Repeat
    if EndPos > StringLength then Exit;
    if TempString[EndPos] = ',' then Inc(CommaCount);
    Inc(EndPos);
  Until CommaCount = Finish - Start + 1;
  Result := Copy(TempString, StartPos, EndPos - StartPos - 1);
end;

Heath
0
 
iwatkinsAuthor Commented:
Easy when you know how !

Things are clear, and it works.

Cheers

Cono
0
 
kretzschmarCommented:
hi,

a other way, with strings


function selectpart(source, Starting, Ending : String) : String;
begin
  If pos(Starting,source) = 0 then
    result := 'Start not found'
  else
    If pos(Ending,source) = 0 then
      result := 'End not found'
    else
      If pos(Ending,source) < pos(Starting,source) then
        result := 'End before Start'
      else
        result := copy(source,pos(starting,source),pos(Ending,source)+Length(Ending)-pos(starting,source));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  edit4.text := SelectPart(edit1.text,edit2.text,edit3.text);
end;


meikl
0
 
kretzschmarCommented:
Hi,

it seems i am a little late for this q

meikl
0
 
heathprovostCommented:
No offense intended, But his cono's functin does NOT do what you asked.  for example:

ExtractSubString('1,2,3,4,5,6,7,8,9,0', 1, 9) returns

"1,2,3,4,5,6,7,8,9," not "1,2,3,4,5,6,7,8,9"

also

ExtractSubString('100,200,300,400,500,600,700,800,900,1000', 1, 9) returns

NOTHING!

I wrote my function to be generic, as in ALL input in the format you specified returns valid results.  I think you should be more careful evaluating things next time.

Heath
0
 
MatveyCommented:
Ooooh, man, I'm a bit late... Do you want to see what a beauty I made? Well, I have nobody else to show this to, so here it is:
________________________________________________________________
function ExtractSubString(MainString: string; Start, Finish: integer): string;
var
  AP: TParser;
  SS: TStringStream;
  CI, StartPos, EndPos: integer;
begin
  SS := TStringStream.Create(MainString);
  AP := TParser.Create(SS);
  CI := 1;
  with AP do begin
    repeat
      if Token = ',' then begin inc(CI); NextToken; end;
      if CI <= Start then StartPos := SourcePos;
    until (NextToken = #0) or (CI >= Finish);
    EndPos := SourcePos;
  end;
  Result := Copy(MainString, StartPos+1, EndPos-StartPos);
  AP.Free;
  SS.Free;
end;
________________________________________________________________
0
 
heathprovostCommented:
Hey Matvey, that one real nice :)
0
 
kretzschmarCommented:
Matvey,

really late, but a tricky way

meikl
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.