How to get the current sentence?

General TRichView support forum. Please post your questions here
Post Reply
lovethisgame
Posts: 8
Joined: Sat Sep 13, 2008 1:36 am

How to get the current sentence?

Post by lovethisgame »

Hi! I want to get the current sentence, but I do not have any idea about how to achieve it.
Thanks. :D
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

For simple functions returning the current word, line, etc. see the unit RVGetText (or RVGetTextW for Unicode versions).
As for the sentence, it's more complicated, and the result depends on the definition of "sentence".
Recently I was asked to create a procedure expanding the current selection to a sentence.
A sentence is delimited either with '.', '?', '!' characters followed by a space or end of line or end of doc (for example, sentences can be finished with '!? ' or '... '), or any non-text item (picture), or a line break.

Not extensively tested, but I hope it's ok.

Code: Select all

procedure ExpandToSentence(rve: TCustomRichViewEdit);
var ItemNo1, ItemNo2, Offs1, Offs2: Integer;
    Found: Boolean;
    s: String;
 
    // Returns True is the specified position contains punctuation followed by
    // a space, of line end, or doc end.
    function HasSpaceAfter(ItemNo, Offs: Integer): Boolean;
    var s: String;
    begin
      Result := True;
      while ItemNo<rve.ItemCount do begin
        s := rve.GetItemText(ItemNo);
        while (Offs<=Length(s)) and (s[Offs] in ['.','!','?']) do
          inc(Offs);
        if Offs<Length(s) then begin
          Result := s[Offs]=' ';
          exit;
        end;
        inc(ItemNo);
        if (ItemNo<rve.ItemCount) then begin
          if (rve.GetItemStyle(ItemNo)<0) or rve.IsFromNewLine(ItemNo) then
            exit;
          Offs := rve.GetOffsBeforeItem(ItemNo);
        end;
      end;
    end;
 
    // Moves the position to the right, skipping punctuation
    procedure SkipPunct(var AItemNo, AOffs: Integer);
    var s: String;
        ItemNo, Offs: Integer;
    begin
      ItemNo := AItemNo;
      Offs := AOffs;
      while ItemNo<rve.ItemCount do begin
        s := rve.GetItemText(ItemNo);
        while (Offs<=Length(s)) and (s[Offs] in ['.','!','?']) do
          inc(Offs);
        AItemNo := ItemNo;
        AOffs := Offs;
        if Offs<Length(s) then
          exit;
        inc(ItemNo);
        if (ItemNo<rve.ItemCount) and
          ((rve.GetItemStyle(ItemNo)<0) or rve.IsFromNewLine(ItemNo)) then
          exit;
      end;
    end;
 
begin
  rve := rve.TopLevelEditor;
  // assigning the selection bounds to ItemNo1, Offs1, ItemNo2, Offs2
  if rve.SelectionExists then
    rve.GetSelectionBounds(ItemNo1, Offs1, ItemNo2, Offs2, True)
  else begin
    ItemNo1 := rve.CurItemNo;
    ItemNo2 := ItemNo1;
    Offs1 := rve.OffsetInCurItem;
    Offs2 := Offs1;
  end;
  // expanding the top bound (Item1, Offs1)
  while True do begin
    if Offs1>=rve.GetOffsBeforeItem(ItemNo1) then begin
      if rve.GetItemStyle(ItemNo1)<0 then
        break;
      s := rve.GetItemText(ItemNo1);
      Found := False;
      while Offs1>1 do begin
        if (s[Offs1-1] in ['.','!','?']) and HasSpaceAfter(ItemNo1, Offs1) then begin
          Found := True;
          break;
        end;
        dec(Offs1);
      end;
      if Found then
        break;
    end;
    if rve.IsFromNewLine(ItemNo1) then
      break;
    dec(ItemNo1);
    Offs1 := rve.GetOffsAfterItem(ItemNo1)
  end;
  // expanding the bottom bound (Item2, Offs2)
  while ItemNo2<rve.ItemCount do begin
    if Offs2<=rve.GetOffsAfterItem(ItemNo2) then begin
      if rve.GetItemStyle(ItemNo2)<0 then
        break;
      s := rve.GetItemText(ItemNo2);
      Found := False;
      while Offs2<=Length(s) do begin
        if (s[Offs2] in ['.','!','?']) and HasSpaceAfter(ItemNo2, Offs2) then begin
          Found := True;
          SkipPunct(ItemNo2, Offs2);
          break;
        end;
        inc(Offs2);
      end;
      if Found then
        break;
    end;
    if (ItemNo2+1=rve.ItemCount) or rve.IsFromNewLine(ItemNo2+1) then
      break;
    inc(ItemNo2);
    Offs2 := rve.GetOffsBeforeItem(ItemNo2)
  end;
  rve.SetSelectionBounds(ItemNo1, Offs1, ItemNo2, Offs2);
  rve.Invalidate;
end;
After calling this procedure, use GetSelText to get the selected text.
lovethisgame
Posts: 8
Joined: Sat Sep 13, 2008 1:36 am

Thanks.

Post by lovethisgame »

Thanks a lot. Your code works well.
Post Reply