format-reading strings lazarus / 10-Designer ---------------------------------------------------------------------- cazzajay · 2009-08-11 12:01 i have a string which is "XXXABCYYY" where XXX  and YYY are numbers (not the same) which may be any combination of 1, 2, or 3 digits i.e. 1 2 3 4 10 11 12 13 123 124 125 etc the question is - how do i extract just the ABCYYY bit? if i use rightstr(myString, 6) it works if the YYY is a 3 digit number, but obviously if its 2 or 1 digits i will get XABCYY or XXABCY respectively. is there a way to enforce the rightstr to start at A rather than a fixed number of characters from the right hand side? Any advice would be great, thanks! ---------------------------------------------------------------------- gerardus · 2009-08-11 16:44 If you are uncertain of how many digits there are, you can skip chars as long as they are digits, and then copy from that position Code: [Select]i := 1; myResultString := ''; while (myString[i] in ['0'..'9']) and (i <= 3) do   inc(i); MyResultString := Copy(MyString, i, Length(MyString)-i); Regards, Gerard. ---------------------------------------------------------------------- cazzajay · 2009-08-11 17:20 hi first thanks for the reply, it seems like a useful tip for future!  however, what if the initial bit to skip contains other characters such as spaces and symbols eg: XXX: ABCYYY where XXX is 1, 2, or 3 digits as above?  Would this work with that? ---------------------------------------------------------------------- gerardus · 2009-08-11 17:32 Quotehowever, what if the initial bit to skip contains other characters such as spaces and symbols eg No, obviously. There's no way I can help if you change the rules on the fly.  Do you have an exact grammar or spec of what goes in one of the input strings? ---------------------------------------------------------------------- cazzajay · 2009-08-11 18:07 hehe. touche! ok ill explain exactly what im after doing. i have a listbox filled with the text as follows: Factor XX: NameYYY and im after extracting the NameYYY bit when the user double clicks on the box using something like str := listbox1.items[listbox1.itemindex]; except i want str to not contain the word "Factor XX:" thanks for ur time ---------------------------------------------------------------------- theo · 2009-08-11 18:15 Method depends whether the String NameYYY may contain characters outside of the ASCII range like öäüè etc. Otoh if, it's always like above, you could take the ':' as separator. Is it this way? Then use the Pos function. ---------------------------------------------------------------------- cazzajay · 2009-08-11 18:40 always in ascii.  how do i use pos to identify the colon as a separator? given XX could be 1 or 2 digits, and YYY could be 1, 2, or 3 digits? ---------------------------------------------------------------------- theo · 2009-08-11 18:44 Pos simply finds the first occurence of a character or a string and returns its position. http://www.freepascal.org/docs-html/rtl/system/pos.html ---------------------------------------------------------------------- cazzajay · 2009-08-11 18:46 legendary! thankya ---------------------------------------------------------------------- eny · 2009-08-11 19:24 Get rid of this parsing nighmare: use regular expressions!! Built for Delphi; works perfectly with Lazarus. ---------------------------------------------------------------------- theo · 2009-08-11 21:36 Quote from: eny on August 11, 2009, 09:24:48 pmGet rid of this parsing nighmare: use regular expressions!! It's nice but for a newbie finding a colon in a string it's overkill, don't you think? ---------------------------------------------------------------------- cazzajay · 2009-08-11 22:28 Quote from: theo on August 11, 2009, 11:36:17 pmQuote from: eny on August 11, 2009, 09:24:48 pmGet rid of this parsing nighmare: use regular expressions!! It's nice but for a newbie finding a colon in a string it's overkill, don't you think? well its a steep learning curve, but im climbing slowly and steadily... ---------------------------------------------------------------------- cazzajay · 2009-08-11 23:03 OK here's what ive done: for the text in the listbox item "Factor 1: ABCXXX" where XXX could be 1, 2 or 3 digits long, ive done this code: var i: integer; final: string; begin i := pos(': ', listbox1.Items[listbox1.itemindex]); final := ansimidstr(listbox1.items[listbox1.itemindex], i, length(listbox1.items[listbox1.itemindex]));  showmessage(final); end; using the ansimidstr that used to exist in old delphi (which doesnt exist in lazarus).  So...anyone know whats the equivalent in lazarus? ive tried just midstr (as ansileftstr is just leftstr in lazarus, etc.) to no avail...? ---------------------------------------------------------------------- cazzajay · 2009-08-11 23:07 solved it, i didnt have strutils in my uses. d'oh! ---------------------------------------------------------------------- eny · 2009-08-12 07:23 Quote from: theo on August 11, 2009, 11:36:17 pmIt's nice but for a newbie finding a colon in a string it's overkill, don't you think? If it's only about finding a colon in a string, ever, you're right. But this thread started with detecting a certain pattern in a substring. And then it went on with searching for a colon in a string and extracting text based on that position. Everytime the requirements change (e.g. 'now I want the text that is after the second colon...') you have to change the code and make it more complex. As you can see in the solution above, it gets ugly really fast! Sure, regular expressions have a learning curve. But it's definitely worth the effort. And I have faith in cazzajay ---------------------------------------------------------------------- cazzajay · 2009-08-12 12:48 ---------------------------------------------------------------------- Marc · 2009-08-12 19:05 if you use lclproc, you can use the following too:Code: [Select]begin   source := 'wueeuoieu: abcxxx';   part := GetPart([':'], [], source, false, false);   // part is now ' abcxxx' end; ---------------------------------------------------------------------- Graeme · 2009-08-12 22:42 The tiOPF project available on SourceForge has a tiUtils.pas unit. There are some very handy utility functions in there. For your problem, there is tiToken(..) method, which could be used as follows:  s := 'name: graeme';  r1 := tiToken(s, ':', 1); // r1 now contains 'name'  r2 := tiToken(s, ':', 2); // r2 now contains 'graeme' There is also a much more advanced tiTokenLibrary.pas unit which supports more options. All of these could be copied and used in other projects without requiring tiOPF - they are simply value added functions/classes. ---------------------------------------------------------------------- gerardus · 2009-08-13 08:57 You now have a few options, let me add one more: If the amount of information that is to be linked to each of the items of the list is going to be important, or may change, what about using objects? You can define a class to hold all the info you need: e.g. TMYClass = Class(TObject)   Factor: String;   Name: String;   Whatever: Integer;   ... end; Adding  Items to the listbox is simple: Code: [Select]var  aThing: TMyClass; begin  aThing := TMyClass.Create;  aThing.Factor := 'XXX';  aThing.Name := 'YYY';  ListBox.Items.AddObject('Factor: '+aThing.Factor+' Name: '+aThing.Name, aThing); end; Retrieving the info from the list item: Code: [Select]var  aThing: TMyClass; begin  aThing := TMyClass(ListBox.Items.Objects[i]);  ShowMessage(aThing.Name); Don't forget to free the objects once you're done using the listbox (e.g. OnFormDestroy) : Code: [Select]procedure ClearListBox; var   i: integer; begin   for i := 0 to ListBox.Items.Count-1 do     TMYClass(ListBox.Items.Objects[i]).Free; end; This may be much more efficient and manageable than parsing the text of the listbox items. Regards, Gerard. ---------------------------------------------------------------------- eny · 2009-08-13 09:14 Quote from: gerardus on August 13, 2009, 10:57:38 amDon't forget to free the objects once you're done using the listbox Assuming the data for the objects comes frome 'somewhere outside', you could use a TObjectList (unit contnrs) instead. Populate the ListBox with the items from the object list. And when closing the application, simply free the objectlist. A TObjectList autofrees all objects when destroyed. ---------------------------------------------------------------------- theo · 2009-08-13 09:24 This thread reminds me of this tv-spot (german) http://www.youtube.com/watch?v=zl6WgCKfDuU The little girl thinks she has a surprise egg, and asks "what's inside?" As an answer she gets the whole plethora of "nutrition facts" which sounds scary to her. ---------------------------------------------------------------------- gerardus · 2009-08-13 09:57 He he, sometimes it's better not to ask. ---------------------------------------------------------------------- eny · 2009-08-13 14:41 Maybe we need a warning sign for Lazarus: do not open Pandora's box ---------------------------------------------------------------------- cazzajay · 2009-08-14 09:44 i think its a homage to the size of the community out there devoted to good quality pascal programming...