Link to home
Start Free TrialLog in
Avatar of T0masz
T0masz

asked on

String split

Hey, I have a string like 234234some describtion.txt Id like to seperate it where the number ends, how would I go about doing it? I was thinking about checking every single char in the string if its a number then if its not start copying the char to a string.

Tom
Avatar of rbohac
rbohac

function FirstLetterInString(s:String):integer;
var x:Integer;
begin
  //Returns the index of the first letter in a string;
  Result := 0;
  for x:=1 to length(s) do
    if ((ord(s[x]) < 48) or (ord(s[x]) > 57)) then
      begin
      Result := x;
      break;
      end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var idx:Integer;
s,firstpart,secondpart:String;
begin
  s := '234234some';
  idx := FirstLetterInString(s);
  if idx > 0 then
    begin
    firstpart := Copy(s,1,idx -1);
    secondpart := copy(s,idx,length(s));
    ShowMessage('First Part = '+FirstPart);
    ShowMessage('Second Part = '+SecondPart);
    end
    else
    showmessage('Error');
end;
Basically FirstLetterInString returns the index of the first character that is non-numeric. the ord function will return the ascii decimal number of a character (see http://www.asciitable.com for a reference chart)

Then once you have that you can simply copy our the parts you need
procedure TForm1.FormActivate(Sender: TObject);
var
 S: String;
 S1: String;  //numer
 S2: String; //alpha
 I: Integer;
begin
 S1:= '';
 S2:= '';
 S:= '234234some describtion.txt';
 for I:= 1 to Length(S) do
  if S[I] in ['0','1','2','3','4','5','6','7','8','9'] then
   S1:= S1 + S[I]
  else
  begin
   S2:= Copy(S,I,Length(S));
   Break;
  end;
  ShowMessage(S + #10#13 + S1 + #10#13 + S2);
end;
sorry, i did my testing in the Form's OnActivate event

You can just use this portion anywhere you like (Example: Button's OnCLick event)

Shane

var
 S: String;
 S1: String;  //numer
 S2: String; //alpha
 I: Integer;
begin
 S1:= '';
 S2:= '';
 S:= '234234some describtion.txt';
 for I:= 1 to Length(S) do
  if S[I] in ['0','1','2','3','4','5','6','7','8','9'] then
   S1:= S1 + S[I]
  else
  begin
   S2:= Copy(S,I,Length(S));
   Break;
  end;
  ShowMessage(S + #10#13 + S1 + #10#13 + S2);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  strings      : TStringList;
  counter      : Integer;
  strLine      : String;
  varString    : String;
  varInteger   : Integer;
  linec        : Integer;
begin
  // create the string and load from file
  strings := TStringList.Create;
  strings.LoadFromFile('C:\test.txt');
  // loop through the strings
  for counter := 0 to strings.Count - 1 do
    begin
      strLine := Strings[counter];
      // pos indicates where digits start
      linec   := 0;
      repeat
        Inc(linec);
      until (strLine[linec] in ['0'..'9']);
      varString  := Copy(strLine, 1, linec-1);
      varInteger := StrToInt(Copy(strLine, linec, length(strLine) - linec + 1));
      // add to string grid
      StringGrid1.Cells[0, counter] := varString;
      StringGrid1.Cells[1, counter] := IntToStr(varInteger);
    end;
end;
function IsNumber(C: String): Boolean;
begin
     result:=false;
     if (Pos(C,'123456789')>0) then result:=true;
end;


function GetNumberStrfromTXTString(ThisString: String) : string;
var   SubStr       :  String;
      i,j          :  Integer;
begin
    i:=1;    // ignore #0
     while ((IsNumber(ThisString[i])=true) and (i<=length(ThisString))) do
           begin
           inc(i);
           SubStr := Copy(ThisString,1 ,i-1);
           end;
    result:= SubStr;
end;


procedure TForm1.Button3Click(Sender: TObject);
begin
     Edit7.Text := GetNumberStrfromTXTString(Edit8.Text);
end;


many, many ways to solve this problem ...   .-)
Avatar of T0masz

ASKER

shaneholmes is the closest one, Im just trying to change it so I would pass it a string with '234234some describtion.txt' and it would return me an array (TStrings) S1[0] would be the string and s1[2] would be the rest... how would I set a return value to be tstrings?

Tom
function IsNumber(C: String): Boolean;
begin
     result:=false;
     if (Pos(C,'123456789')>0) then result:=true;
end;


function GetTextStrfromTXTString(ThisString: String) : string;
var   SubStr       :  String;
      i,j          :  Integer;
begin
    i:=1;    // ignore #0
     while ((IsNumber(ThisString[i])=true) and (i<=length(ThisString))) do
           begin
           inc(i);
           //  If you want to get the rest , just edit here ... ->
           SubStr := Copy(ThisString,i ,length(ThisString)-i-1);
           end;
    result:= SubStr;
end;
Avatar of kretzschmar
well a just from head function

function GetNumber(AStr : String) : String;
var i : integer;
begin
  result := '';
  if AStr <> '' then
  begin
    i := 1;
    while i < length(AStr) and (Astr[i] in ['0'..'9']) do inc(i);
    result := copy(AStr,1,i-1);
  end;
end;

meikl ;-)
>it would return me an array (TStrings) S1[0] would be the string and s1[2]

another solution

function GetNumber(var AStr : String) : String;
var i : integer;
begin
  result := '';
  if AStr <> '' then
  begin
    i := 1;
    while i < length(AStr) and (Astr[i] in ['0'..'9']) do inc(i);
    result := copy(AStr,1,i-1);
    ASTr := copy(AStr,i,maxlongint);
  end;
end;

--> returns the number
--> AStr holds now only the rest (Number excluded)

just not tested

meikl ;-)
Something like this?


function FirstLetterInString(s:String):integer;
var x:Integer;
begin
  //Returns the index of the first letter in a string;
  Result := 0;
  for x:=1 to length(s) do
    if ((ord(s[x]) < 48) or (ord(s[x]) > 57)) then
      begin
      Result := x;
      break;
      end;
end;

procedure SeperateString(s:String; var slist:TStringList);
var idx:Integer;
firstpart,secondpart:String;
begin
  idx := FirstLetterInString(s);
  if idx > 0 then
    begin
    sList.Add(Copy(s,1,idx -1));
    sList.Add(copy(s,idx,length(s)));
    end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var idx:Integer;
slist:TStringList;
s:String;
begin
  s := '234234some';
  sList := TStringList.Create;
  try
    SeperateString(s,slist);
    ShowMessage(sList[0]);
    ShowMessage(sList[1]);
    finally
    slist.free;
  end;

end;
oops.. you can remove the variables "firstpart" and "secondpart" from SeperateString
Avatar of T0masz

ASKER

   while i < length(AStr) and (Astr[i] in ['0'..'9']) do inc(i);
it shows "opperator is not applicable to this operand type"
>while i < length(AStr) and (Astr[i] in ['0'..'9']) do inc(i);

missed some brackets

while (i < length(AStr)) and (Astr[i] in ['0'..'9']) do inc(i);

should work now

meikl ;-)
Is there something wrong with my code? Have you tried it? Is it not what you asked for?
ASKER CERTIFIED SOLUTION
Avatar of kretzschmar
kretzschmar
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of T0masz

ASKER

function GetMain(var AStr : String) : String;
var i : integer;
begin
  result := '';
  if AStr <> '' then
  begin
    i := 1;
    while (i <= length(AStr)) and (Astr[i] = '.') do inc(i);
    result := copy(AStr,1,i-1);
    ASTr := copy(AStr,i,maxlongint);
  end;
end;

I just changed it to split by the '.' character to return the main part of the filename ( without the .txt ) why doesnt it work?
Ps  meikl gets the points his example worked great and I can understand it :)

Tom
>I just changed it to split by the '.' character to return the main part of the filename ( without the .txt )
>why doesnt it work?

because this loop

   while (i <= length(AStr)) and (Astr[i] = '.') do inc(i);

ends if the first char is no '.'

just change it to

   while (i <= length(AStr)) and (Astr[i] <> '.') do inc(i);

and it should work (not tested yet)

glad you like my solution :-)
(but the others may work also, i guess)

meikl ;-)
hmm,  your orginal question said nothing about an array ......

Dont you think a split would have been warranted - at a minimum?

<SMILE>

Shane
right. both of my solutions did exactly what you asked for. even though you changed your requirements half way through it