[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Delphi2010: How to split string which contains space and " "

Posted on 2011-04-29
18
Medium Priority
?
5,301 Views
Last Modified: 2012-05-11
hi all,

i have a string as followed:

Test01:"C:\with a space\anything_here"  Test02:"C:\with a space\with a space\anything_here"  Test03:C:\without\a\space

how do i split it into a array which contains following three element:
Test01:"C:\with a space\anything_here"
Test02:"C:\with a space\with a space\anything_here"
Test03:C:\without\a\space

i have tried to split the string, but i get just following parts:
Test01:"C:\with
a
space\anything_here"

any suggestion is appreciate. I would like to use " " and blank space to split the string.
thanks,

wantime
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Split(Delimiter: Char; Str: string; ListOfStrings: TStrings) ;
  private

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  commands: TStringList;
begin
  commands := TStringList.Create;
  Split(' ', Edit1.Text, commands) ;
  Edit2.Text := commands[0];
  Edit3.Text := commands[1];
  Edit4.Text := commands[2];
end;

procedure TForm1.Split(Delimiter: Char; Str: string; ListOfStrings: TStrings) ;
begin
   ListOfStrings.Clear;
   ListOfStrings.Delimiter     := Delimiter;
   ListOfStrings.DelimitedText := Str;
end;


end.

Open in new window

0
Comment
Question by:wantime
  • 5
  • 4
  • 4
  • +2
18 Comments
 
LVL 32

Expert Comment

by:Ephraim Wangoya
ID: 35492948
try this
procedure TForm1.Button1Click(Sender: TObject);
var
  commands: TStringList;
begin
  commands := TStringList.Create;
  Split(Edit1.Text, commands) ;
  Edit2.Text := commands[0];
  Edit3.Text := commands[1];
  Edit4.Text := commands[2];
  commands.Free;
end

procedure TForm1.Split(Str: string; ListOfStrings: TStrings) ;
var
  temp: string;
  I: integer;
begin
  ListOfStrings.Clear;
  ListOfStrings.Delimiter := ',';
  ListOfStrings.StrictDelimiter := True;
  ListOfStrings.QuoteChar := '"';
  ListOfStrings.DelimitedText := Str;

  temp := StringReplace(Str, 'Test', ',Test', [rfReplaceAll]);
  if temp[1] = ',' then
    temp[1] := ' ';

  ListOfStrings.DelimitedText := Trim(temp);
end;

Open in new window

0
 
LVL 32

Expert Comment

by:Ephraim Wangoya
ID: 35493033
Sorry, I assigned it twice
procedure TForm1.Button1Click(Sender: TObject);
var
  commands: TStringList;
begin
  commands := TStringList.Create;
  Split(Edit1.Text, commands) ;
  Edit2.Text := commands[0];
  Edit3.Text := commands[1];
  Edit4.Text := commands[2];
  commands.Free;
end

procedure TForm1.Split(Str: string; ListOfStrings: TStrings) ;
var
  temp: string;
  I: integer;
begin
  ListOfStrings.Clear;
  ListOfStrings.Delimiter := ',';
  ListOfStrings.StrictDelimiter := True;
  ListOfStrings.QuoteChar := '"';

  temp := StringReplace(Trim(Str), 'Test', ',Test', [rfReplaceAll]);
  if temp[1] = ',' then
    temp[1] := ' ';

  ListOfStrings.DelimitedText := Trim(temp);
end;

Open in new window

0
 
LVL 24

Expert Comment

by:jimyX
ID: 35493069
Is your format constant? Is it always going to be Test01, Test02, Test03,...etc?
uses StrUtils;

procedure TForm1.Button1Click(Sender: TObject);
var
  strlst:TStrings;
  Str:String;
  i:integer;
begin
  str:='Test01:"C:\with a space\anything_here"  Test02:"C:\with a space\with a space\anything_here"  Test03:C:\without\a\space';
  strlst:=TStringlist.Create;
  i:=2;

  repeat
    strlst.Add(copy(str,1,pos('Test'+Format('%.2d', [i])+':',str)-3));
    delete(str,1,pos('Test'+Format('%.2d', [i])+':',str)-1);
    inc(i);
  until posex('Test',str,3) <= 0;

  strlst.Add(copy(str,1,length(str)));
  delete(str,1,length(str));

  showmessage(strlst.Text);
  strlst.Free;
end;

Open in new window

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 35495542
use a different delimiter
do not use space as delimiter

this is same as if somebody asks you to count words in a document when somebody else has put a space between each 2 letters
you will ask them to remove extra spaces or use something else to delimit by
0
 
LVL 32

Expert Comment

by:Ephraim Wangoya
ID: 35498159

If you will not have an identifier such as "TestX" in your examples, then use a proper delimiter as Geert mentioned above
You could use a semicolon and set StrictDelimiter to True
0
 
LVL 46

Expert Comment

by:aikimark
ID: 35501790
1. replace all '" Test' with '"^Test' and store the resulting string in a TStringList
2. use the .DelimitedText property of the TStringList with a '^' character as the delimiter, placing the result in another TStringList variable.
0
 

Author Comment

by:wantime
ID: 35503198
thank you for your answer.

as i mentioned, I would like to use " " and blank space to split the string.

"Test" is just a example, they can also be different. just like:

X:"C:\with a space\anything_here"  Y:"C:\with a space\with a space\anything_here"  Z:C:\without\a\space

the thing i am sure it that between each block there exist a blank. If this block has space in it, symbol " " will then be used.

0
 

Author Comment

by:wantime
ID: 35503239
btw, symbol " " will be used, only if there are space in block. If there is no space in the block, " " will not be used.

first and second space has blank, so " " is used.

X:"C:\with a space\anything_here"  Y:"C:\with a space\with a space\anything_here"

the third one doesn't has space , so it looks like Z:C:\without\a\space

if there is a method to make the block which has space as a unit, then the whole string should be possible to be splited by using space as delimiter.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 35503257
using StrictDelimiter is the easiest

how do you fill up your stringlist  ?

function Test: string;
var X, Y: TStrings;
begin
  X := TStringList.Create;
  Y := TStringList.Create;
  try
    X.Delimiter := ' ';
    Y.Delimiter := ' ';
    X.StrictDelimiter := True;
    Y.StrictDelimiter := True;
    X.Add('test 1');
    X.Add('test 2');
    Y.Add(X.DelimitedText);
    X.Clear;
    X.Add('test 3');
    X.Add('test 4);
    Y.Add(X.DelimitedText);
    Result := Y.DelimitedText;
  finally
    Y.Free;
    X.Free;
  end;
end;
0
 
LVL 24

Accepted Solution

by:
jimyX earned 500 total points
ID: 35503298
I updated my code:
uses StrUtils;

procedure TForm1.Button1Click(Sender: TObject);
var
  strlst:TStrings;
  Str:String;
  i:integer;
begin
  str:='X:"C:\with a space\anything_here"  Y:"C:\with a space\with a space\anything_here"  Z:C:\without\a\space';
  strlst:=TStringlist.Create;

  repeat
    strlst.Add(copy(str,1,posEx(':',str,pos('\',Str))-3));
    delete(str,1,posEx(':',str,pos('\',Str))-2);
  until posex(':\',str,6) <= 0;

  strlst.Add(copy(str,1,length(str)));
 
  showmessage(strlst.Text);
  strlst.Free;
end;

Open in new window

I can't test it ATM.
0
 
LVL 38

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 500 total points
ID: 35503306
maybe this will help you follow better
this sample is based on your input

a buildstring to show you how you should add the data
and splitstring to show you how you should extract it again

if your delphi version does not have the StrictDelimiter,
then you have a version of delphi which always will split at the space

 
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function BuildString: string;
var X, Y: TStrings;
begin
  X := TStringList.Create;
  Y := TStringList.Create;
  try
    X.Delimiter := ' ';
    Y.Delimiter := ' ';
    X.StrictDelimiter := True;
    Y.StrictDelimiter := True;
    X.Values['TEST1'] := 'C:\with a space\anything_here';
    X.Values['TEST2'] := 'C:\with a space\with a space\anything_here';
    X.Values['TEST3'] := 'C:\without\a\space';
    Y.Add(X.DelimitedText);
    X.Clear;
    X.Values['TEST4'] := 'C:\with a space\anything_here';
    X.Values['TEST5'] := 'C:\with a space\with a space\anything_here';
    X.Values['TEST6'] := 'C:\without\a\space';
    Y.Add(X.DelimitedText);
    Result := Y.DelimitedText;
  finally
    Y.Free;
    X.Free;
  end;
end;

procedure SplitString(Total: string; List: TStrings);
var X, Y: TStrings;
  I: Integer;
begin
  X := TStringList.Create;
  Y := TStringList.Create;
  try
    X.Delimiter := ' ';
    Y.Delimiter := ' ';
    X.StrictDelimiter := True;
    Y.StrictDelimiter := True;
    X.DelimitedText := Total;
    for I := 0 to X.Count - 1 do
    begin
      Y.DelimitedText := X[I];
      List.AddStrings(Y);
    end;
  finally
    Y.Free;
    X.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var temp: string;
var List: TStrings;
begin
  Temp := BuildString;
  Memo1.Lines.Add('Result of buildstring: ');
  Memo1.Lines.Add(Temp);
  List := TStringList.Create;
  try
    SplitString(Temp, List);
    Memo1.Lines.Add('Result of split string');
    Memo1.Lines.AddStrings(List);

    Memo1.Lines.Add('Extracting specific values : ');
    Memo1.Lines.Add('TEST1 = "' + List.Values['TEST1'] + '"');
  finally
    List.Free;
  end;
end;

end.

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 35503505
forgot to post the output:
 
Memo1
Result of buildstring: 
"""TEST1=C:\with a space\anything_here"" ""TEST2=C:\with a space\with a space\anything_here"" TEST3=C:\without\a\space" """TEST4=C:\with a space\anything_here"" ""TEST5=C:\with a space\with a space\anything_here"" TEST6=C:\without\a\space"
Result of split string
TEST1=C:\with a space\anything_here
TEST2=C:\with a space\with a space\anything_here
TEST3=C:\without\a\space
TEST4=C:\with a space\anything_here
TEST5=C:\with a space\with a space\anything_here
TEST6=C:\without\a\space
Extracting specific values : 
TEST1 = "C:\with a space\anything_here"

Open in new window

0
 

Author Comment

by:wantime
ID: 35503755
sorry, i should explain my question more clear.

the string which need to be splited is not constant, but they have a format like followed:

Format I:

[A-Z][:]["][A-Z and space]["]

Format II:

[A-Z][:][A-Z]

that means, "Test01,Test02, Test03" and "X, Y, Z" that i mentioned above is just a example, the length of the word changed. The background info for this question are followed: In a text field one could input differnt Commands, these Commands is seperated by space. If Command contains space, Format I will be used, if not, Format II will be used. The format is there and i could not change it. what  I need to resolve is to splite the whole string into differnt rows/block like i mentioned before. (after the string is splited, an application will be called to execute each Command. But this is another topic which we don't need to discuss here.)
0
 
LVL 46

Expert Comment

by:aikimark
ID: 35504156
@Delphi experts

Since you're working with paths, it is possible for a path to contain two consecutive spaces (or more) and still be a legal path.

You should probably test the possibility of the no-spaces path not being the last one in the input string.

======
@wantime

Will you support UNC paths or will you always have a drive letter?

Path names can contain characters other than A-Z.  Your pattern definition is incomplete.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 35504223
i'm lost, you are asking something completely different now ?

if you care to be precise with your question ...
you will get an acurate and precise answer

this is making it difficult to follow !
0
 
LVL 46

Assisted Solution

by:aikimark
aikimark earned 500 total points
ID: 35504506
@Delphi experts

I suspect that the only reliable methods for parsing these strings are:
1. Using a Regular Expression engine
2. Within an iteration loop, look for ':\' and then back up to find the prior double space characters (or start of the string).  I would recommend starting at the end of the string, moving to the front.  Peel the parsed elements off the back, in  the inverse of the way that was show in http#35503298 (front-peel-off)
3. Use TStringLists to parse by a ':\' delimiter and then parse the items to reconstruct the items and restore the ':\' to the paths.
Example:
If you started with this:
'X:"C:\with a space\anything_here"  Y:"C:\with a space\with a space\anything_here"  Z:C:\without\a\space'

Open in new window


The first parse would produce TStringList items like this:
'X:"C'
'with a space\anything_here"  Y:"C'
'with a space\with a space\anything_here"  Z:C'
'without\a\space'

Open in new window


For the [1] through [.count-2] items, you look for the last two double space charcters ' ' and move whatever follows to the start of the next item along with a ':\' string that was removed by the first parsing step.  I assume that setting the length of the string = position where we found the last double-space character (-1) would be the quickest way to clean up the trailing part of the item.  

The [0] item is prepended to the [1] item along with the missing ':\'

The [0] item is deleted.
0
 
LVL 32

Assisted Solution

by:Ephraim Wangoya
Ephraim Wangoya earned 500 total points
ID: 35509156

Nobody is going to be able to give a proper solution until we get proper sample data, actual sample data

first example was
Test01:"C:\with a space\anything_here"  Test02:"C:\with a space\with a space\anything_here"  Test03:C:\without\a\space

Second example was
X:"C:\with a space\anything_here"  Y:"C:\with a space\with a space\anything_here"  Z:C:\without\a\space

third example was
Format I: [A-Z][:]["][A-Z and space]["],  Format II: [A-Z][:][A-Z]
which could be
  abracadabra:"now you see it-now you don't"

If the format is clearly defined, then a proper solution will be formulated in no time. Is it a list of file paths, in which case its simply
c:\dir1\dir2 "c:\long dir1\another long dir" c: z: f:\ k:\1\2\3

Once you give us the proper input, I'm sure one of the experts here will give a very satisfactory algorithm
0
 

Author Comment

by:wantime
ID: 35510580
At the begin i was not sure, what the format should be look like. your suggestion have already help to resolve the problem, after i redefine the format in my codes.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Integration Management Part 2
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses
Course of the Month19 days, 3 hours left to enroll

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question