Is there a way to automatically capitalize the first letter of a sentence as we go on typing. ie. the first letter after the full stop and space.
thanks in advance
Capitalize first letter of a sentence
Re: Capitalize first letter of a sentence
Sergey Tkachenko wrote: ↑Sat Oct 29, 2016 3:21 pm Sorry for the delay.
Two main approaches are possible:
1) like in MS Word, a word is capitalized after it is finished
2) like in many other applications, a word is capitalized immediately on typing.
(1) is more complicated to implement, so I chose (2). This procedure is already not simple, so I do not want to complicate it even more.
The code is below. Actually, I think I'll create a new component, TRVKeyboardManager, that can be linked to TRichViewEdit or TSRichViewEdit and processes things like auto-capitalization, auto making opening/closing quotes, replacing - to –, etc.
The code is below.
This code requires Delphi 2009 or newer.
The main function is CapitalizeWord. It has parameters:Code: Select all
{$I RV_Defs.inc} uses Character; type TRVCapitalizeState = (rvcsWord, rvcsWhitespace); function IsEndOfSentencePunctuation(Ch: Char): Boolean; begin case Ord(Ch) of $00021, $0002E, $0003F, $00589, $0061F, $006D4, $00700..$00702, $007F9, $00964, $00965, $0104A, $0104B, $01362, $01367, $01368, $0166E, $01803, $01809, $01944, $01945, $01AA8..$01AAB, $01B5A, $01B5B, $01B5E, $01B5F, $01C3B, $01C3C, $01C7E, $01C7F, $0203C, $0203D, $02047..$02049, $02E2E, $03002, $0A4FF, $0A60E, $0A60F, $0A6F3, $0A6F7, $0A876, $0A877, $0A8CE, $0A8CF, $0A92F, $0A9C8, $0A9C9, $0AA5D..$0AA5F, $0AAF0, $0AAF1, $0ABEB, $0FE52, $0FE56, $0FE57, $0FF01, $0FF0E, $0FF1F, $0FF61{, $11047, $11048, $110BE, $110BF, $110C0, $110C1, $11141..$11143, $111C5, $111C6}: Result := True; else Result := False; end; end; function RvIsLetterOrDigit(Ch: Char): Boolean; inline; begin {$IFDEF RICHVIEWDEFXE4} Result := Ch.IsLetterOrDigit {$ELSE} Result := Character.IsLetterOrDigit(Ch); {$ENDIF} end; function RvIsWhiteSpace(Ch: Char): Boolean; inline; begin {$IFDEF RICHVIEWDEFXE4} Result := Ch.IsWhiteSpace {$ELSE} Result := Character.IsWhiteSpace(Ch); {$ENDIF} end; function RvIsLower(Ch: Char): Boolean; inline; begin {$IFDEF RICHVIEWDEFXE4} Result := Ch.IsLower {$ELSE} Result := Character.IsLower(Ch); {$ENDIF} end; function RvToUpper(Ch: Char): Char; inline; begin {$IFDEF RICHVIEWDEFXE4} Result := Ch.ToUpper {$ELSE} Result := Character.ToUpper(Ch); {$ENDIF} end; function ShouldCapitalizeWord(rve: TCustomRichViewEdit; CapitalizeFirstCellChar, CapitalizeLists: Boolean): Boolean; var ItemNo, Offs: Integer; S: String; State: TRVCapitalizeState; WhiteSpaceLength: Integer; function FinishItem: Boolean; // result: continue? begin Result := not rve.IsFromNewLine(ItemNo); end; function StartItem(ChangeOffs: Boolean): Boolean; // result: continue? begin Result := ItemNo >= 0; if not Result then exit; if rve.GetItemStyle(ItemNo) < 0 then begin Result := (rve.GetItemStyle(ItemNo) = rvsTab) and (State = rvcsWhitespace); if Result then inc(WhiteSpaceLength); end else begin Result := not rve.Style.TextStyles[rve.GetItemStyle(ItemNo)].IsSymbolCharset; if Result then begin S := rve.GetItemText(ItemNo); if ChangeOffs then Offs := Length(S); end; end; end; begin Result := False; rve := rve.TopLevelEditor; if rve.SelectionExists then exit; ItemNo := rve.CurItemNo; Offs := rve.OffsetInCurItem; if (Offs <= rve.GetOffsBeforeItem(ItemNo)) then if rve.IsFromNewLine(ItemNo) then begin Result := True; if not CapitalizeFirstCellChar and (rve.RVData.GetSourceRVData is TRVTableCellData) and (ItemNo = 0) then Result := False; exit; end else begin dec(ItemNo); if ItemNo < 0 then exit else Offs := rve.GetOffsAfterItem(ItemNo); end; dec(Offs); State := rvcsWhitespace; WhiteSpaceLength := 0; if not StartItem(False) then begin if CapitalizeLists and (ItemNo >=0) and (rve.GetItemStyle(ItemNo) = rvsListMarker) then Result := True; exit; end; while True do begin if (rve.GetItemStyle(ItemNo) >= 0) and (Offs > 0) then begin case State of rvcsWhitespace: if RvIsWhiteSpace(S[Offs]) then inc(WhiteSpaceLength) else if IsEndOfSentencePunctuation(S[Offs]) then begin if WhiteSpaceLength = 0 then exit; State := rvcsWord; end else exit; rvcsWord: begin Result := RvIsLetterOrDigit(S[Offs]); exit; end; end; dec(Offs); end else begin if not FinishItem then exit; dec(ItemNo); if not StartItem(True) then exit; end; end; end; procedure InsertReplacedChar(const Ch1, Ch2: Char; rve: TCustomRichViewEdit); var ItemNo, Offs: Integer; begin rve := rve.TopLevelEditor; ItemNo := rve.CurItemNo; Offs := rve.OffsetInCurItem; rve.InsertText(Ch1); rve.BeginUndoGroup(rvutInsert); rve.SetUndoGroupMode(True); rve.SetSelectionBounds(ItemNo, Offs, rve.CurItemNo, rve.OffsetInCurItem); rve.DeleteSelection; rve.InsertText(Ch2); rve.SetUndoGroupMode(False); end; function CapitalizeWord(rve: TCustomRichViewEdit; var Key: Char; CapitalizeFirstCellChar, CapitalizeLists: Boolean): Boolean; begin if RvIsLower(Key) and ShouldCapitalizeWord(rve, True, True) then begin InsertReplacedChar(Key, RVToUpper(Key), rve); Key := #0; Result := True; end else Result := False; end;
- CapitalizeFirstCellChar: capitalize the first character in table cells
- CapitalizeLists: capitalize the first character in bulleted and numbered paragraphs.
Call it in OnKeyPress:Code: Select all
procedure TForm3.RichViewEdit1KeyPress(Sender: TObject; var Key: Char); begin ... CapitalizeWord(RichViewEdit1, Key, True, True); end;
Re: Capitalize first letter of a sentence
Hi sergey,
Sorry, i forgot to mention the Delphi version. I want this to be done in Delphi-7 actually. So is there a way for that.
Regards,
Sorry, i forgot to mention the Delphi version. I want this to be done in Delphi-7 actually. So is there a way for that.
Regards,
-
- Site Admin
- Posts: 17569
- Joined: Sat Aug 27, 2005 10:28 am
- Contact:
Re: Capitalize first letter of a sentence
Here is the version for Delphi 5, 6, 7 and 2007.
How to use:
Code: Select all
uses RVUni, RVTypes;
type
TRVCapitalizeState = (rvcsWord, rvcsWhitespace);
function IsEndOfSentencePunctuation(Ch: TRVUnicodeChar): Boolean;
begin
case Ord(Ch) of
$00021, $0002E, $0003F, $00589, $0061F, $006D4,
$00700..$00702, $007F9, $00964, $00965, $0104A, $0104B,
$01362, $01367, $01368, $0166E, $01803, $01809,
$01944, $01945, $01AA8..$01AAB, $01B5A, $01B5B,
$01B5E, $01B5F, $01C3B, $01C3C, $01C7E, $01C7F,
$0203C, $0203D, $02047..$02049, $02E2E, $03002,
$0A4FF, $0A60E, $0A60F, $0A6F3, $0A6F7,
$0A876, $0A877, $0A8CE, $0A8CF, $0A92F,
$0A9C8, $0A9C9, $0AA5D..$0AA5F, $0AAF0, $0AAF1,
$0ABEB, $0FE52, $0FE56, $0FE57, $0FF01, $0FF0E,
$0FF1F, $0FF61{, $11047, $11048, $110BE, $110BF,
$110C0, $110C1, $11141..$11143, $111C5, $111C6}:
Result := True;
else
Result := False;
end;
end;
function RvIsLetterOrDigit(Ch: TRVUnicodeChar): Boolean;
begin
Result := IsCharAlphaNumericW(Ch);
end;
function RvIsWhiteSpace(Ch: TRVUnicodeChar): Boolean;
begin
case Ord(Ch) of
$0020, $0009..$000D, $00A0, $0085, $2028, $2029,
$1680, $2000..$200A, $202F, $205F, $3000:
Result := True
else
Result := False;
end;
end;
function RvIsLower(Ch: TRVUnicodeChar): Boolean; overload;
begin
Result := IsCharLowerW(Ch)
end;
function RvToUpper(Ch: TRVUnicodeChar): TRVUnicodeChar;
var
S: TRVUnicodeString;
begin
S := Ch;
CharUpperW(PRVUnicodeChar(S));
Result := S[1];
end;
function ShouldCapitalizeWord(rve: TCustomRichViewEdit;
CapitalizeFirstCellChar, CapitalizeLists: Boolean): Boolean;
var
ItemNo, Offs: Integer;
S: TRVUnicodeString;
State: TRVCapitalizeState;
WhiteSpaceLength: Integer;
function FinishItem: Boolean; // result: continue?
begin
Result := not rve.IsFromNewLine(ItemNo);
end;
function StartItem(ChangeOffs: Boolean): Boolean; // result: continue?
begin
Result := ItemNo >= 0;
if not Result then
exit;
if rve.GetItemStyle(ItemNo) < 0 then
begin
Result := (rve.GetItemStyle(ItemNo) = rvsTab) and (State = rvcsWhitespace);
if Result then
inc(WhiteSpaceLength);
end
else
begin
Result := not rve.Style.TextStyles[rve.GetItemStyle(ItemNo)].IsSymbolCharset;
if Result then
begin
S := rve.GetItemTextW(ItemNo);
if ChangeOffs then
Offs := Length(S);
end;
end;
end;
begin
Result := False;
rve := rve.TopLevelEditor;
if rve.SelectionExists then
exit;
ItemNo := rve.CurItemNo;
Offs := rve.OffsetInCurItem;
if (Offs <= rve.GetOffsBeforeItem(ItemNo)) then
if rve.IsFromNewLine(ItemNo) then
begin
Result := True;
if not CapitalizeFirstCellChar and (rve.RVData.GetSourceRVData is TRVTableCellData) and (ItemNo = 0) then
Result := False;
exit;
end
else
begin
dec(ItemNo);
if ItemNo < 0 then
exit
else
Offs := rve.GetOffsAfterItem(ItemNo);
end;
dec(Offs);
State := rvcsWhitespace;
WhiteSpaceLength := 0;
if not StartItem(False) then
begin
if CapitalizeLists and (ItemNo >=0) and
(rve.GetItemStyle(ItemNo) = rvsListMarker) then
Result := True;
exit;
end;
while True do
begin
if (rve.GetItemStyle(ItemNo) >= 0) and (Offs > 0) then
begin
case State of
rvcsWhitespace:
if RvIsWhiteSpace(S[Offs]) then
inc(WhiteSpaceLength)
else if IsEndOfSentencePunctuation(S[Offs]) then
begin
if WhiteSpaceLength = 0 then
exit;
State := rvcsWord;
end
else
exit;
rvcsWord:
begin
Result := RvIsLetterOrDigit(S[Offs]);
exit;
end;
end;
dec(Offs);
end
else
begin
if not FinishItem then
exit;
dec(ItemNo);
if not StartItem(True) then
exit;
end;
end;
end;
procedure InsertReplacedChar(const Ch1, Ch2: TRVUnicodeChar; rve: TCustomRichViewEdit);
var
ItemNo, Offs: Integer;
begin
rve := rve.TopLevelEditor;
ItemNo := rve.CurItemNo;
Offs := rve.OffsetInCurItem;
rve.InsertTextW(Ch1);
rve.BeginUndoGroup(rvutInsert);
rve.SetUndoGroupMode(True);
rve.SetSelectionBounds(ItemNo, Offs, rve.CurItemNo, rve.OffsetInCurItem);
rve.DeleteSelection;
rve.InsertTextW(Ch2);
rve.SetUndoGroupMode(False);
end;
function CapitalizeWord(rve: TCustomRichViewEdit; var Key: Char;
CodePage: Cardinal; CapitalizeFirstCellChar, CapitalizeLists: Boolean): Boolean;
var
S: TRVUnicodeString;
begin
Result := False;
S := RVU_AnsiToUnicode(CodePage, Key);
if Length(S) <> 1 then
exit;
if RvIsLower(S[1]) and ShouldCapitalizeWord(rve, True, True) then
begin
InsertReplacedChar(S[1], RVToUpper(S[1]), rve);
Key := #0;
Result := True;
end;
end;
How to use:
Code: Select all
procedure TForm3.RichViewEdit1KeyPress(Sender: TObject; var Key: Char);
begin
...
CapitalizeWord(RichViewEdit1, Key, RVU_GetKeyboardCodePage, True, True);
end;
Re: Capitalize first letter of a sentence
Thanks for the help. I will implement and revert.