I am trying to get a routine that will find a string that does not follow a parentheses. For instance if the file open in the RichEdit contains these lines of CNC code, I want it to find the first two and ignore the third. In the second line it should only find and highlight the first occurrence of the search string. The search string (mach.TOOL_CHANGE_CALL) in this example is 'T'.
N1T1M6
N1T1M6(1/4-20 TAP .5 DP.)
(1/4-20 TAP .5 DP.)
I have gotten this far, but am stumped.
procedure TMainForm.ToolButton3Click(Sender: TObject); // find tool number
var
row:integer;
sel_str:string;
par:integer;
tool:integer;
tool_flag:integer ;
line_counter:integer;
tool_pos:integer;
line_begin:integer;
RE:TRichEdit;
begin
RE:=(ActiveMDIChild as TMDIChild).RichEdit1;
line_counter:=0;
tool_flag:=0;
tool_pos:=0;
row:=SendMessage(RE.Handle,EM_LINEFROMCHAR,-1, RE.SelStart);
while tool_flag =0 do
begin
RE.Perform(EM_LINESCROLL,0,line_counter);
sel_str := RE.Lines[Line_counter];
tool:=pos(mach.TOOL_CHANGE_CALL,sel_str);
par:=pos('(',sel_str);
if par=0 then
par:=pos('[',sel_str);
tool_pos:=tool_pos+length(sel_str);
if (tool>0) and (par = 0) then
begin
RE.SetFocus;
tool_pos:=tool_pos + line_counter-1;
line_begin:=tool_pos-tool;
RE.SelStart := line_begin;
RE.SelLength := Length(sel_str);
tool_flag:=1;
end;
inc (line_counter);
end;
end;
The results I get is that it will ignore the third string, but will also ignore the second string as well. It also will not find subsequent occurrences of the string in the file, it just starts back at the beginning to the text and finds the first one again. How can I get it to find the second example and then find the next 'T' at the next click of the button? I also need it to highlight the entire line the search string was found on.
Given the samples you posted, you can use Delphi (XE and higher) regular expressions to match the text you've indicated. Here, I've put the three sample lines you've shown into a TMemo
(Memo1
in the code below), evaluate the regular expression, and put the matches found into Memo2
- as long as your TRichEdit
contains only plain text, you can use the same code by replacing Memo1
and Memo2
with RichEdit1
and RichEdit2
respectively.
I've updated the code in both snippets to show how to get the exact position (as an offset from the first character) and length of the match result; you can use this to highlight the match in the richedit using SelStart
and SelLength
.
uses
RegularExpressions;
procedure TForm1.Button1Click(Sender: TObject);
var
Regex: TRegEx;
MatchResult: TMatch;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('N1T1M6');
Memo1.Lines.Add('N1T1M6(1/4-20 TAP .5 DP.)');
Memo1.Lines.Add('(1/4-20 TAP .5 DP.)');
Memo2.Clear;
// See the text below for an explanation of the regular expression
Regex := TRegEx.Create('^\w+T\w+', [roMultiLine]);
MatchResult := Regex.Match(Memo1.Lines.Text);
while MatchResult.Success do
begin
Memo2.Lines.Add(MatchResult.Value +
' Index: ' + IntToStr(MatchResult.Index) +
' Length: ' + IntToStr(MatchResult.Length));
MatchResult := MatchResult.NextMatch;
end;
end;
This produces the following results:
If you're using a version of Delphi that doesn't include regular expression support, you can use the free TPerlRegEx
with some minor code changes to produce the same results:
uses
PerlRegEx;
procedure TForm1.Button1Click(Sender: TObject);
var
Regex: TPerlRegEx;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('N1T1M6');
Memo1.Lines.Add('N1T1M6(1/4-20 TAP .5 DP.)');
Memo1.Lines.Add('(1/4-20 TAP .5 DP.)');
Memo2.Clear;
Regex := TPerlRegEx.Create;
try
Regex.RegEx := '^\w+T\w+';
Regex.Options := [preMultiLine];
Regex.Subject := Memo1.Lines.Text;
if Regex.Match then
begin
repeat
Memo2.Lines.Add(Regex.MatchedText +
' Offset: ' + IntToStr(Regex.MatchedOffset) +
' Length: ' + IntToStr(Regex.MatchedLength));
until not Regex.MatchAgain;
end;
finally
Regex.Free;
end;
end;
The regular expression above (^\w+T\w+
) means:
Options: ^ and $ match at line breaks Assert position at the beginning of a line (at beginning of the string or after a line break character) «^» Match a single character that is a “word character” (letters, digits, and underscores) «\w+» Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» Match the character “T” literally «T» Match a single character that is a “word character” (letters, digits, and underscores) «\w+» Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» Created with RegexBuddy
You can find a decent tutorial regarding regular expressions here. The tool I used for working out the regular expression (and actually producing much of the Delphi code for both examples) was RegexBuddy - I'm not affiliated with the company that produces it, but just a user of that product.