Marco Gasi
asked on
Regex issue (maybe...)
In my application I load a file (which is the result of an export from the Windows registry) in a TListBox (see this question for further details: https://www.experts-exchange.com/questions/28408002/Loading-large-file-in-a-TRichEdit.html?anchorAnswerId=39988447#a39988447). I use regular expression to detect paths within the file and I check if the path exists in the current machine: if not, the listbox item is highlighted.
While adding items to the listbox, I build a second stringlist which holds the number of item withnon existent paths, so I can use this info with two buttons (Next and Prev) to browse the listbox jumping from a wrong path to another.
The problem is that the code to highlight draws colored background on certain items which have not been inserted in the listbox which holds indexes.
Maybe seeing the code can help you to understand me better:-)
Fill Listbox:
Draw background:
And finally the code to navigate the listbox:
I attach a sample file I'm testing with (its name is passed by the calling form which opens the form where the listbox is in).
I also attach two screenshots of the just created form and the form after the click on the Next button: as you can see, it doesn't jump the the first highlighted line of the first screenshot but to line 108.
Thanks to all
Marco
HKCU-basic.txt
While adding items to the listbox, I build a second stringlist which holds the number of item withnon existent paths, so I can use this info with two buttons (Next and Prev) to browse the listbox jumping from a wrong path to another.
The problem is that the code to highlight draws colored background on certain items which have not been inserted in the listbox which holds indexes.
Maybe seeing the code can help you to understand me better:-)
Fill Listbox:
procedure TfrmIncorrectPaths.FormShow(Sender: TObject);
var
rx: TPerlRegEx;
I: Integer;
sr: TStreamReader;
n: Integer;
Buf: array[1..8191] of Char; { 4K buffer }
begin
lblCount.Caption := '';
try
slOriginal.LoadFromFile(FName);
if (bitActual = '64') and (bitBackup = '32') then
AdjustProgramDir32to64(slOriginal);
if (bitActual = '32') and (bitBackup = '64') then
AdjustProgramDir64to32(slOriginal);
rx := TPerlRegEx.Create;
try
rx.Options := [preCaseLess,preExtended];
rx.RegEx := '\b[a-z]:\\ # Drive'#10 +
'(?:[^\\/:*?"<>|\r\n]+\\)* # Folder'#10 +
'[^\\/:*?"<>|\r\n]* # File';
for I := 0 to slOriginal.Count - 1 do
begin
rx.Subject := slOriginal[I];
if rx.Match then
begin
lbxRegFile.Items.Add(slOriginal[I]);
if (not DirectoryExists(ExtractFilePath(rx.MatchedText))) then
begin
if slTokens.IndexOfName(IntToStr(I)) = - 1 then
slTokens.Add(IntToStr(I)+'='+'1')
else
begin
n := StrToInt(slTokens.ValueFromIndex[slTokens.IndexOfName(IntToStr(I))]);
n := n + 1;
slTokens.ValueFromIndex[slTokens.IndexOfName(IntToStr(I))] := IntToStr(n);
end;
end;
end;
end;
finally
rx.Free;
end;
finally
end;
end;
Draw background:
procedure TfrmIncorrectPaths.lbxRegFileDrawItem(Control: TWinControl;
Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
myColor: TColor;
myBrush: TBrush;
rx: TPerlRegEx;
I: Integer;
begin
myBrush := TBrush.Create;
try
rx := TPerlRegEx.Create;
try
rx.Options := [preCaseLess,preExtended];
rx.RegEx := '\b[a-z]:\\ # Drive'#10 +
'(?:[^\\/:*?"<>|\r\n]+\\)* # Folder'#10 +
'[^\\/:*?"<>|\r\n]* # File';
rx.Subject := lbxRegFile.Items[Index];
myColor := clWhite;
if rx.Match then
if (not DirectoryExists(ExtractFilePath(rx.MatchedText))) then
myColor := clAqua;
with (Control as TListBox).Canvas do
begin
myBrush.Style := bsSolid;
myBrush.Color := myColor;
Winapi.Windows.FillRect(handle, Rect, myBrush.Handle) ;
Brush.Style := bsClear;
TextOut(Rect.Left, Rect.Top,
(Control as TListBox).Items[Index]) ;
end;
finally
rx.Free;
end;
finally
MyBrush.Free;
end;
end;
And finally the code to navigate the listbox:
procedure TfrmIncorrectPaths.imgNextTokenClick(Sender: TObject);
var
CurrentIndex: Integer;
begin
if (lbxRegFile.ItemIndex < StrToInt(slTokens.Names[0]))
or (lbxRegFile.ItemIndex > StrToInt(slTokens.Names[slTokens.Count-1])) then
begin
// ShowMessage(slTokens.Names[0]);
CurrentIndex := 0;
lbxRegFile.ItemIndex := StrToInt(slTokens.Names[0])
end
else
begin
CurrentIndex := slTokens.IndexOfName(IntToStr(lbxRegFile.ItemIndex));
// ShowMessage(slTokens.Names[CurrentIndex+1]);
lbxRegFile.ItemIndex := StrToInt(slTokens.Names[CurrentIndex+1]);
end;
lblCount.Caption := 'Line '+IntToStr(lbxRegFile.ItemIndex)+' - Wrong values: '+slTokens.ValueFromIndex[CurrentIndex+1];
end;
procedure TfrmIncorrectPaths.imgPrevTokenClick(Sender: TObject);
var
CurrentIndex: Integer;
begin
if (lbxRegFile.ItemIndex < StrToInt(slTokens.Names[0]))
or (lbxRegFile.ItemIndex > StrToInt(slTokens.Names[slTokens.Count-1])) then
begin
CurrentIndex := 0;
lbxRegFile.ItemIndex := StrToInt(slTokens.Names[slTokens.Count-1]);
end
else
begin
CurrentIndex := slTokens.indexOfName(IntToStr(lbxRegFile.ItemIndex));
lbxRegFile.ItemIndex := StrToInt(slTokens.Names[CurrentIndex-1]);
end;
lblCount.Caption := 'Line '+IntToStr(lbxRegFile.ItemIndex)+' wrong values: '+slTokens.ValueFromIndex[CurrentIndex-1];
end;
I attach a sample file I'm testing with (its name is passed by the calling form which opens the form where the listbox is in).
I also attach two screenshots of the just created form and the form after the click on the Next button: as you can see, it doesn't jump the the first highlighted line of the first screenshot but to line 108.
Thanks to all
Marco
HKCU-basic.txt
Are you sure your regex pattern is giving you the correct path to check?
ASKER
No, I see some non existent path is not highlighted: for instance in line 13 there is non existent path C:\Users\marqus\AppData\Lo cal\Micros oft but it's not highlighted whereas following paths are correctly highlighted.
Anyway, I'm going to look for ItemData property.
Anyway, I'm going to look for ItemData property.
ASKER
About ItemData, I don't think that's useful for me: my navigation buttons don't have to jump from aline to the following line. They need to know the index of the following line with a wrong path, so in my econd data structure I store only the indexes of the items with a wrong path. Perhaps I'm wrong, but it deosn't seem ItemData can be ueful in this...
Normally the ItemData values are all zero. However, if you assign a non-zero value to an item in your listbox (.SetItemData method if memory serves me well), you can use the .GetItemData to navigate to any item in the listbox. You would only assign a value if the directory was not found. It would be at the same place in your code where you highlight the item.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Are you using the Tlistbox or TCustomlistbox? I looked for a code example and it seems that the GetItemdata() method is only available when you derived from the TCustomListbox class. So, this might be a 'never mind' situation.
I have played with the regular expression pattern and the (registry slice) text file you posted. It wasn't clear from that playing if your pattern is giving you what you want. Part of that confusion is my ignorance about which lines you need to check.
I have played with the regular expression pattern and the (registry slice) text file you posted. It wasn't clear from that playing if your pattern is giving you what you want. Part of that confusion is my ignorance about which lines you need to check.
Do you need to find the paths that are part of the registry key text?
Example:
[HKEY_CURRENT_USER\SOFTWAR E\Embarcad ero\BDS\12 .0\C:\User s\marqus]
What are you looking for when the text contains multiple paths?
Example:
[HKEY_CURRENT_USER\SOFTWAR E\Embarcad ero\BDS\12 .0\C:\User s\marqus\A ppData\Roa ming\Micro soft\Windo ws\Start Menu\Programs\C:\Users\Mar co\AppData \Roaming\M icrosoft\W indows\Sta rt Menu\Programs\Startup\ Options]
and
$(BDSLIB)\$(Platform)\rele ase;$(BDSU SERDIR)\Im ports;$(BD S)\Imports ;$(BDSCOMM ONDIR)\Dcp ;$(BDS)\in clude;Prog ramFlsRaiz e\CS5\Lib\ RS-XE3\Win 32;C:\RAD Components\Delphi\Jedi XE3\jcl\jcl\lib\d17\win32; C:\RAD Components\Delphi\Jedi XE3\jcl\jcl\source\include ;C:\RAD Components\Delphi\Jedi XE3\jvcl\lib\D17\win32;C:\ RAD Components\Delphi\Jedi XE3\jvcl\common;C:\RAD Components\Delphi\Jedi XE3\jvcl\Resources;C:\RAD Components\Delphi\DCPCrypt Last;C:\RA D Components\Delphi\DCPCrypt Last\Ciphe rs;C:\RAD Components\Delphi\DCPCrypt Last\Hashe s;C:\RAD Components\Delphi\MAX\mxPr otector\Co mponent;C: \RAD Components\Delphi\FoxContr ols;C:\MyP rogramsUNI \Utils;C:\ RAD Components\Delphi\RegEx\TP erlRegEx;C :\MyCompon ents\TmgDi giTimer\so urce;C:\My Components \TmgEasyLo g\source;C :\MyCompon ents\TmgFi leListator \source;C: \MyCompone nts\TmgWeb Updater\so urce;C:\RA D Components\Delphi\Abbrevia 5_1\source ;$(DXVCL)\ Library\RS 17;C:\RAD Components\Delphi\XMLParse r;C:\RAD Components\Delphi\MAX\mxSt orage\COMP ONENT
and
"C:\Users\marqus\AppData\L ocal\Micro soft\Windo ws\C:\User s\Marco\Ap pData\Loca l\Microsof t\Windows\ History\"= "False"
=================
Or, what about text that includes a file name in the path?
Example:
TSourceModul'C:\RAD Components\Delphi\Jedi XE3\jcl\jcl\source\common\ JclIDEUtil s.pas',,
Example:
[HKEY_CURRENT_USER\SOFTWAR
What are you looking for when the text contains multiple paths?
Example:
[HKEY_CURRENT_USER\SOFTWAR
and
$(BDSLIB)\$(Platform)\rele
and
"C:\Users\marqus\AppData\L
=================
Or, what about text that includes a file name in the path?
Example:
TSourceModul'C:\RAD Components\Delphi\Jedi XE3\jcl\jcl\source\common\
ASKER
Take it easy, aikimark :-) In comment ID: 39989087 I said I solved the problem. For the specific issue which has made me open this thread the problem was a trivial error in my code.
Regex works correctly (I have to check another couple of thing and maybe I'll open a new question soon about that). In order to answer to your question, I need to get any incorrect path. I'll be happy to give you more details but this question is public and I would prefer a bit of privacy since I'm working on a commercial software. I don't know how we can speak privately, so if you can tell m, I'll be glad to do it.
About ItemData, I use a TListBox and in fact I saw that CodeCompletion didn't give me nor ItemData property nor GetItemData and SetItemData methods: now I know why :-)
Regex works correctly (I have to check another couple of thing and maybe I'll open a new question soon about that). In order to answer to your question, I need to get any incorrect path. I'll be happy to give you more details but this question is public and I would prefer a bit of privacy since I'm working on a commercial software. I don't know how we can speak privately, so if you can tell m, I'll be glad to do it.
About ItemData, I use a TListBox and in fact I saw that CodeCompletion didn't give me nor ItemData property nor GetItemData and SetItemData methods: now I know why :-)
No problem. I'll stop my playing with this problem. If you open a related question, please post a link to it in this thread. Thanks.
ASKER
Now code is working.
That way, your button code can use the getitemdata method to point to the index of the first/next/prev items in the listbox.