سؤال

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:

Capture of results of above code

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top