1 | unit FormCheck;
|
---|
2 |
|
---|
3 | interface
|
---|
4 |
|
---|
5 | uses
|
---|
6 | Classes, SysUtils, LazFileUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
|
---|
7 | ExtCtrls, ComCtrls, Menus, ActnList, Acronym, RegistryEx, Registry, Common,
|
---|
8 | Generics.Collections, FormEx;
|
---|
9 |
|
---|
10 | type
|
---|
11 | TReportType = (rtNone, rtNote, rtWarning, rtError);
|
---|
12 |
|
---|
13 | TReportItem = class
|
---|
14 | Message: string;
|
---|
15 | Position: TPoint;
|
---|
16 | Kind: TReportType;
|
---|
17 | end;
|
---|
18 |
|
---|
19 | { TReportItems }
|
---|
20 |
|
---|
21 | TReportItems = class(TObjectList<TReportItem>)
|
---|
22 | function AddNew(Message: string; Position: TPoint;
|
---|
23 | Kind: TReportType = rtNone): TReportItem;
|
---|
24 | procedure SaveToCsv(FileName: string);
|
---|
25 | end;
|
---|
26 |
|
---|
27 | { TFormCheck }
|
---|
28 |
|
---|
29 | TFormCheck = class(TFormEx)
|
---|
30 | AGoToLocation: TAction;
|
---|
31 | ASaveToCsv: TAction;
|
---|
32 | ActionList1: TActionList;
|
---|
33 | ButtonLoadFromFile: TButton;
|
---|
34 | ButtonAcronymsContent: TButton;
|
---|
35 | ButtonAcronymsSummary: TButton;
|
---|
36 | ButtonCheck: TButton;
|
---|
37 | CheckBoxCaseSensitive: TCheckBox;
|
---|
38 | EditSummaryStart: TEdit;
|
---|
39 | EditSummaryEnd: TEdit;
|
---|
40 | GroupBox1: TGroupBox;
|
---|
41 | GroupBox2: TGroupBox;
|
---|
42 | Label1: TLabel;
|
---|
43 | Label2: TLabel;
|
---|
44 | LabelAcronymCountContent: TLabel;
|
---|
45 | LabelAcronymCountSummary: TLabel;
|
---|
46 | ListViewReport: TListView;
|
---|
47 | MemoDocument: TMemo;
|
---|
48 | MenuItem1: TMenuItem;
|
---|
49 | MenuItemGoTo: TMenuItem;
|
---|
50 | OpenDialog1: TOpenDialog;
|
---|
51 | PageControl1: TPageControl;
|
---|
52 | Panel1: TPanel;
|
---|
53 | Panel2: TPanel;
|
---|
54 | PopupMenuReport: TPopupMenu;
|
---|
55 | SaveDialog1: TSaveDialog;
|
---|
56 | Splitter1: TSplitter;
|
---|
57 | TabSheetSource: TTabSheet;
|
---|
58 | TabSheetReport: TTabSheet;
|
---|
59 | procedure AGoToLocationExecute(Sender: TObject);
|
---|
60 | procedure ASaveToCsvExecute(Sender: TObject);
|
---|
61 | procedure ButtonAcronymsSummaryClick(Sender: TObject);
|
---|
62 | procedure ButtonAcronymsContentClick(Sender: TObject);
|
---|
63 | procedure ButtonCheckClick(Sender: TObject);
|
---|
64 | procedure ButtonLoadFromFileClick(Sender: TObject);
|
---|
65 | procedure FormCreate(Sender: TObject);
|
---|
66 | procedure FormDestroy(Sender: TObject);
|
---|
67 | procedure FormShow(Sender: TObject);
|
---|
68 | procedure ListViewReportData(Sender: TObject; Item: TListItem);
|
---|
69 | private
|
---|
70 | AcronymDbSummary: TAcronymDb;
|
---|
71 | AcronymDbContent: TAcronymDb;
|
---|
72 | LastDocumentFileName: string;
|
---|
73 | function SearchLine(Lines: TStrings; Text: string; Start: Integer = 0): Integer;
|
---|
74 | function SearchLineReverse(Lines: TStrings; Text: string; Start: Integer = -1): Integer;
|
---|
75 | procedure FindInSummary;
|
---|
76 | procedure FindInContent;
|
---|
77 | function AllowedSideChar(Before, After: Char): Boolean;
|
---|
78 | function ParseMeaning(Acronym, Text: string; StartIndex: Integer;
|
---|
79 | out Meaning: string; DashSeparator: Boolean = False): Boolean;
|
---|
80 | function IsUppercaseAlpha(Text: string): Boolean;
|
---|
81 | function IsLowercaseAlpha(Text: string): Boolean;
|
---|
82 | function IsAlpha(Text: string): Boolean;
|
---|
83 | function IsAcronym(Text: string): Boolean;
|
---|
84 | function IsDigit(Text: Char): Boolean;
|
---|
85 | procedure ReportDifferencies;
|
---|
86 | function WordContainsLetters(Text, Letters: string): Boolean;
|
---|
87 | function StringEqual(Text1, Text2: string): Boolean;
|
---|
88 | procedure ReloadReport;
|
---|
89 | public
|
---|
90 | AcronymDb: TAcronymDb;
|
---|
91 | ReportItems: TReportItems;
|
---|
92 | procedure UpdateInterface;
|
---|
93 | procedure LoadConfig(RegistryContext: TRegistryContext);
|
---|
94 | procedure SaveConfig(RegistryContext: TRegistryContext);
|
---|
95 | end;
|
---|
96 |
|
---|
97 | const
|
---|
98 | ReportTypeString: array[TReportType] of string = ('', 'Note', 'Warning', 'Error');
|
---|
99 |
|
---|
100 |
|
---|
101 | implementation
|
---|
102 |
|
---|
103 | {$R *.lfm}
|
---|
104 |
|
---|
105 | uses
|
---|
106 | FormAcronyms;
|
---|
107 |
|
---|
108 | resourcestring
|
---|
109 | SAcronymCountContent = 'Content acronym count:';
|
---|
110 | SAcronymCountSummary = 'Summary acronym count:';
|
---|
111 | SDuplicateAcronymContent = 'Duplicate acronym %s with "%s" in document body.';
|
---|
112 | SDuplicateAcronymSummary = 'Duplicate acronym %s with "%s" in acronym summary.';
|
---|
113 | SMissingAcronymContent = 'Document body acronym %s with meaning "%s" missing from acronym summary.';
|
---|
114 | SMissingAcronymSummary = 'Summary acronym %s with meaning "%s" missing from document body.';
|
---|
115 | SAcronymContentMultipleMeanings = 'Content acronym %s has multiple meanings: %s.';
|
---|
116 | SAcronymSummaryMultipleMeanings = 'Summary acronym %s has multiple meanings: %s.';
|
---|
117 | SAcronymWithDifferentMeaning = 'Acronym %s has different meaning for content "%s" and for summary "%s".';
|
---|
118 | SAcronymWithDifferentMeaningCount = 'Acronym %s has different meaning count for content (%d) and for summary (%d).';
|
---|
119 | SPluralAcronym = 'Acronym %s is defined as plural in document body.';
|
---|
120 | SPluralAcronymUsed = 'Acronym %s is used as plural in document body.';
|
---|
121 | SSummaryAcronyms = 'Summary acronyms';
|
---|
122 | SContentAcronyms = 'Content acronyms';
|
---|
123 | SAcronymUsedBeforeDefined = 'Acronym %s used before it was defined.';
|
---|
124 | SCSVFilter = 'CSV file (.csv)|*.csv|Any file|*.*';
|
---|
125 |
|
---|
126 | const
|
---|
127 | MinAcronymLength = 2;
|
---|
128 |
|
---|
129 | { TReportItems }
|
---|
130 |
|
---|
131 | function TReportItems.AddNew(Message: string; Position: TPoint;
|
---|
132 | Kind: TReportType = rtNone): TReportItem;
|
---|
133 | begin
|
---|
134 | Result := TReportItem.Create;
|
---|
135 | Result.Message := Message;
|
---|
136 | Result.Position := Position;
|
---|
137 | Result.Kind := Kind;
|
---|
138 | Add(Result);
|
---|
139 | end;
|
---|
140 |
|
---|
141 | procedure TReportItems.SaveToCsv(FileName: string);
|
---|
142 | var
|
---|
143 | I: Integer;
|
---|
144 | F: TStringList;
|
---|
145 | Line: TStringList;
|
---|
146 | begin
|
---|
147 | F := TStringList.Create;
|
---|
148 | Line := TStringList.Create;
|
---|
149 | Line.StrictDelimiter := True;
|
---|
150 | try
|
---|
151 | Line.Clear;
|
---|
152 | for I := 0 to Count - 1 do
|
---|
153 | with TReportItem(Items[I]) do begin
|
---|
154 | Line.Clear;
|
---|
155 | if Position <> Point(0, 0) then
|
---|
156 | Line.Add(IntToStr(Position.X) + ', ' + IntToStr(Position.Y))
|
---|
157 | else Line.Add('');
|
---|
158 | Line.Add(ReportTypeString[Kind]);
|
---|
159 | Line.Add(Message);
|
---|
160 | F.Add(Line.CommaText);
|
---|
161 | end;
|
---|
162 | F.SaveToFile(FileName);
|
---|
163 | finally
|
---|
164 | F.Free;
|
---|
165 | Line.Free;
|
---|
166 | end;
|
---|
167 | end;
|
---|
168 |
|
---|
169 | { TFormCheck }
|
---|
170 |
|
---|
171 | procedure TFormCheck.ButtonCheckClick(Sender: TObject);
|
---|
172 | begin
|
---|
173 | ReportItems.Clear;
|
---|
174 | UpdateInterface;
|
---|
175 | FindInSummary;
|
---|
176 | FindInContent;
|
---|
177 | ReportDifferencies;
|
---|
178 | UpdateInterface;
|
---|
179 | ReloadReport;
|
---|
180 | TabSheetReport.Show;
|
---|
181 | end;
|
---|
182 |
|
---|
183 | procedure TFormCheck.ButtonLoadFromFileClick(Sender: TObject);
|
---|
184 | begin
|
---|
185 | OpenDialog1.InitialDir := ExtractFileDir(LastDocumentFileName);
|
---|
186 | OpenDialog1.FileName := ExtractFileName(LastDocumentFileName);
|
---|
187 | if OpenDialog1.Execute then begin
|
---|
188 | LastDocumentFileName := OpenDialog1.FileName;
|
---|
189 | MemoDocument.Lines.LoadFromFile(OpenDialog1.FileName);
|
---|
190 | TabSheetSource.Show;
|
---|
191 | end;
|
---|
192 | end;
|
---|
193 |
|
---|
194 | procedure TFormCheck.FormCreate(Sender: TObject);
|
---|
195 | begin
|
---|
196 | AcronymDbSummary := TAcronymDb.Create;
|
---|
197 | AcronymDbContent := TAcronymDb.Create;
|
---|
198 | ReportItems := TReportItems.Create;
|
---|
199 | end;
|
---|
200 |
|
---|
201 | procedure TFormCheck.FormDestroy(Sender: TObject);
|
---|
202 | begin
|
---|
203 | FreeAndNil(ReportItems);
|
---|
204 | FreeAndNil(AcronymDbSummary);
|
---|
205 | FreeAndNil(AcronymDbContent);
|
---|
206 | end;
|
---|
207 |
|
---|
208 | procedure TFormCheck.FormShow(Sender: TObject);
|
---|
209 | begin
|
---|
210 | PageControl1.TabIndex := 0;
|
---|
211 | if FileExists(LastDocumentFileName) then
|
---|
212 | MemoDocument.Lines.LoadFromFile(LastDocumentFileName);
|
---|
213 | UpdateInterface;
|
---|
214 | end;
|
---|
215 |
|
---|
216 | procedure TFormCheck.ListViewReportData(Sender: TObject; Item: TListItem);
|
---|
217 | begin
|
---|
218 | if Item.Index < ReportItems.Count then
|
---|
219 | with ReportItems[Item.Index] do begin
|
---|
220 | if Position <> Point(0, 0) then
|
---|
221 | Item.Caption := IntToStr(Position.X) + ', ' + IntToStr(Position.Y)
|
---|
222 | else Item.Caption := '';
|
---|
223 | Item.Data := ReportItems[Item.Index];
|
---|
224 | Item.SubItems.Add(ReportTypeString[Kind]);
|
---|
225 | Item.SubItems.Add(Message);
|
---|
226 | end;
|
---|
227 | end;
|
---|
228 |
|
---|
229 | procedure TFormCheck.ButtonAcronymsContentClick(Sender: TObject);
|
---|
230 | var
|
---|
231 | FormAcronyms: TFormAcronyms;
|
---|
232 | begin
|
---|
233 | FormAcronyms := TFormAcronyms.Create(Self);
|
---|
234 | try
|
---|
235 | FormAcronyms.AcronymDb := AcronymDb;
|
---|
236 | FormAcronyms.Acronyms := AcronymDbContent.Acronyms;
|
---|
237 | FormAcronyms.Caption := SContentAcronyms;
|
---|
238 | FormAcronyms.ShowModal;
|
---|
239 | finally
|
---|
240 | FreeAndNil(FormAcronyms);
|
---|
241 | end;
|
---|
242 | end;
|
---|
243 |
|
---|
244 | procedure TFormCheck.ButtonAcronymsSummaryClick(Sender: TObject);
|
---|
245 | var
|
---|
246 | FormAcronyms: TFormAcronyms;
|
---|
247 | begin
|
---|
248 | FormAcronyms := TFormAcronyms.Create(Self);
|
---|
249 | try
|
---|
250 | FormAcronyms.AcronymDb := AcronymDb;
|
---|
251 | FormAcronyms.Acronyms := AcronymDbSummary.Acronyms;
|
---|
252 | FormAcronyms.Caption := SSummaryAcronyms;
|
---|
253 | FormAcronyms.ShowModal;
|
---|
254 | finally
|
---|
255 | FreeAndNil(FormAcronyms);
|
---|
256 | end;
|
---|
257 | end;
|
---|
258 |
|
---|
259 | procedure TFormCheck.ASaveToCsvExecute(Sender: TObject);
|
---|
260 | begin
|
---|
261 | SaveDialog1.InitialDir := ExtractFileDir(LastDocumentFileName);
|
---|
262 | SaveDialog1.DefaultExt := '.csv';
|
---|
263 | SaveDialog1.FileName := ExtractFileNameWithoutExt(ExtractFileName(LastDocumentFileName)) + SaveDialog1.DefaultExt;
|
---|
264 | SaveDialog1.Filter := SCSVFilter;
|
---|
265 | if SaveDialog1.Execute then begin
|
---|
266 | ReportItems.SaveToCsv(SaveDialog1.FileName);
|
---|
267 | end;
|
---|
268 | end;
|
---|
269 |
|
---|
270 | procedure TFormCheck.AGoToLocationExecute(Sender: TObject);
|
---|
271 | begin
|
---|
272 | if Assigned(ListViewReport.Selected) then
|
---|
273 | with TReportItem(ListViewReport.Selected.Data) do
|
---|
274 | if Position <> Point(0, 0) then begin
|
---|
275 | MemoDocument.CaretPos := Position;
|
---|
276 | TabSheetSource.Show;
|
---|
277 | end;
|
---|
278 | end;
|
---|
279 |
|
---|
280 | function TFormCheck.SearchLine(Lines: TStrings; Text: string; Start: Integer = 0): Integer;
|
---|
281 | begin
|
---|
282 | Result := Start;
|
---|
283 | while (Result < Lines.Count) and (Pos(Text, Lines[Result]) = 0) do Inc(Result);
|
---|
284 | if Result >= Lines.Count then Result := -1;
|
---|
285 | end;
|
---|
286 |
|
---|
287 | function TFormCheck.SearchLineReverse(Lines: TStrings; Text: string;
|
---|
288 | Start: Integer = -1): Integer;
|
---|
289 | begin
|
---|
290 | if Start = -1 then Result := Lines.Count - 1
|
---|
291 | else Result := Start;
|
---|
292 | while (Result >= 0) and (Pos(Text, Lines[Result]) = 0) do Dec(Result);
|
---|
293 | end;
|
---|
294 |
|
---|
295 | procedure TFormCheck.FindInSummary;
|
---|
296 | var
|
---|
297 | AcronymSectionStart: Integer;
|
---|
298 | AcronymSectionEnd: Integer;
|
---|
299 | I: Integer;
|
---|
300 | Line: string;
|
---|
301 | Acronym: string;
|
---|
302 | Meaning: string;
|
---|
303 | Index: Integer;
|
---|
304 | begin
|
---|
305 | AcronymDbSummary.Acronyms.Clear;
|
---|
306 |
|
---|
307 | AcronymSectionStart := SearchLineReverse(MemoDocument.Lines, EditSummaryStart.Text);
|
---|
308 | if AcronymSectionStart <> -1 then begin
|
---|
309 | AcronymSectionEnd := SearchLine(MemoDocument.Lines, EditSummaryEnd.Text, AcronymSectionStart + 1);
|
---|
310 | if AcronymSectionEnd <> -1 then begin
|
---|
311 | Acronym := '';
|
---|
312 | for I := AcronymSectionStart + 1 to AcronymSectionEnd - 1 do begin
|
---|
313 | Line := Trim(MemoDocument.Lines[I]);
|
---|
314 | Line := StringReplace(Line, #9, ' ', [rfReplaceAll]);
|
---|
315 | if Line <> '' then begin
|
---|
316 | if (Acronym <> '') and IsUppercaseAlpha(Acronym) then begin
|
---|
317 | Meaning := Line;
|
---|
318 | end else begin
|
---|
319 | Index := Pos(' ', Line);
|
---|
320 | if Index > 0 then begin
|
---|
321 | Acronym := Copy(Line, 1, Index - 1);
|
---|
322 | Meaning := Trim(Copy(Line, Index + 1, Length(Line)));
|
---|
323 | end else begin
|
---|
324 | if Acronym = '' then Acronym := Line
|
---|
325 | else Meaning := Line;
|
---|
326 | end;
|
---|
327 | end;
|
---|
328 | if (Acronym <> '') and IsUppercaseAlpha(Acronym) and (Meaning <> '') then begin
|
---|
329 | if Assigned(AcronymDbSummary.SearchAcronym(Acronym, Meaning)) then
|
---|
330 | ReportItems.AddNew(Format(SDuplicateAcronymSummary, [Acronym, Meaning]), Point(0, I), rtWarning)
|
---|
331 | else AcronymDbSummary.AddAcronym(Acronym, Meaning);
|
---|
332 | Acronym := '';
|
---|
333 | Meaning := '';
|
---|
334 | end;
|
---|
335 | end;
|
---|
336 | end;
|
---|
337 | end;
|
---|
338 | end;
|
---|
339 | end;
|
---|
340 |
|
---|
341 | procedure TFormCheck.FindInContent;
|
---|
342 | var
|
---|
343 | Text: string;
|
---|
344 | Index: Integer;
|
---|
345 | State: (stNone, stAcronymUsage, stAcronymDefinition);
|
---|
346 | Acronym: string;
|
---|
347 | AcronymCharBefore: Char;
|
---|
348 | AcronymCharAfter: Char;
|
---|
349 | Lines: TStringList;
|
---|
350 | HasUpperCase: Boolean;
|
---|
351 | HasLowerCase: Boolean;
|
---|
352 | I: Integer;
|
---|
353 | J: Integer;
|
---|
354 | Line: string;
|
---|
355 | Meaning: string;
|
---|
356 | Meaning1: string;
|
---|
357 | Meaning2: string;
|
---|
358 | HasMeaning1: Boolean;
|
---|
359 | HasMeaning2: Boolean;
|
---|
360 | Plural: Boolean;
|
---|
361 | StartIndex: Integer;
|
---|
362 | Acro: TAcronym;
|
---|
363 | begin
|
---|
364 | AcronymDbContent.Acronyms.Clear;
|
---|
365 |
|
---|
366 | // Make lowercase lines where all alpha characters are in uppercase
|
---|
367 | // These are usually first level chapter titles or first page text
|
---|
368 | Lines := TStringList.Create;
|
---|
369 | Lines.Assign(MemoDocument.Lines);
|
---|
370 | for I := 0 to Lines.Count - 1 do begin
|
---|
371 | HasLowerCase := False;
|
---|
372 | HasUpperCase := False;
|
---|
373 | Line := Lines[I];
|
---|
374 | for J := 1 to Length(Line) do begin
|
---|
375 | if IsUppercaseAlpha(Line[J]) then HasUpperCase := True;
|
---|
376 | if IsLowercaseAlpha(Line[J]) then HasLowerCase := True;
|
---|
377 | end;
|
---|
378 | if HasUpperCase and not HasLowerCase then
|
---|
379 | Lines[I] := LowerCase(Lines[I]);
|
---|
380 | end;
|
---|
381 |
|
---|
382 | // Find acronyms usage in text
|
---|
383 | Text := Lines.Text;
|
---|
384 | Text := StringReplace(Text, #9, ' ', [rfReplaceAll]);
|
---|
385 | Text := StringReplace(Text, LineEnding, ' ', [rfReplaceAll]);
|
---|
386 | Index := 1;
|
---|
387 | AcronymCharBefore := ' ';
|
---|
388 | AcronymCharAfter := ' ';
|
---|
389 | State := stNone;
|
---|
390 | StartIndex := 0;
|
---|
391 | Acronym := '';
|
---|
392 | repeat
|
---|
393 | if State = stAcronymUsage then begin
|
---|
394 | if not IsUppercaseAlpha(Text[Index]) then begin
|
---|
395 | if Text[Index] = 's' then begin
|
---|
396 | Acronym := Acronym + Text[Index];
|
---|
397 | Inc(Index);
|
---|
398 | end;
|
---|
399 | if (Index) < Length(Text) then AcronymCharAfter := Text[Index]
|
---|
400 | else AcronymCharAfter := ' ';
|
---|
401 | State := stNone;
|
---|
402 |
|
---|
403 | // Allow plural acronyms with ending 's' character
|
---|
404 | if (Length(Acronym) >= 1) and (Acronym[Length(Acronym)] = 's') then begin
|
---|
405 | Acronym := Copy(Acronym, 1, Length(Acronym) - 1);
|
---|
406 | Plural := True;
|
---|
407 | end else Plural := False;
|
---|
408 |
|
---|
409 | // Acronyms should not contain numbers
|
---|
410 | if (Length(Acronym) >= MinAcronymLength) and
|
---|
411 | AllowedSideChar(AcronymCharBefore, AcronymCharAfter) then begin
|
---|
412 | // If plural acronym then try to remove ending 's' character from the meaning
|
---|
413 | if Plural then ReportItems.AddNew(Format(SPluralAcronymUsed, [Acronym]), Point(0, 0), rtNote);
|
---|
414 |
|
---|
415 | Acro := AcronymDbContent.Acronyms.SearchByName(Acronym);
|
---|
416 | if not Assigned(Acro) then begin
|
---|
417 | ReportItems.AddNew(Format(SAcronymUsedBeforeDefined, [Acronym]), Point(0, 0), rtNote);
|
---|
418 | AcronymDbContent.AddAcronym(Acronym, '');
|
---|
419 | end;
|
---|
420 | end;
|
---|
421 | end else Acronym := Acronym + Text[Index];
|
---|
422 | end else
|
---|
423 | if State = stAcronymDefinition then begin
|
---|
424 | if Text[Index] = ')' then begin
|
---|
425 | // Allow plural acronyms with ending 's' character
|
---|
426 | if (Length(Acronym) >= 1) and (Acronym[Length(Acronym)] = 's') then begin
|
---|
427 | Acronym := Copy(Acronym, 1, Length(Acronym) - 1);
|
---|
428 | Plural := True;
|
---|
429 | end else Plural := False;
|
---|
430 | if IsAcronym(Acronym) then begin
|
---|
431 | HasMeaning1 := ParseMeaning(Acronym, Text, StartIndex - 1, Meaning1);
|
---|
432 | if HasMeaning1 then Meaning := Meaning1;
|
---|
433 | HasMeaning2 := ParseMeaning(Acronym, Text, StartIndex - 1, Meaning2, True);
|
---|
434 | if HasMeaning2 then Meaning := Meaning2;
|
---|
435 | if HasMeaning1 and HasMeaning2 then begin
|
---|
436 | if Length(Meaning1) > Length(Meaning2) then Meaning := Meaning1
|
---|
437 | else Meaning := Meaning2;
|
---|
438 | end;
|
---|
439 | if HasMeaning1 or HasMeaning2 then begin
|
---|
440 | // If plural acronym then try to remove ending 's' character from the meaning
|
---|
441 | if Plural then ReportItems.AddNew(Format(SPluralAcronym, [Acronym]), Point(0, 0), rtNote);
|
---|
442 | if Plural and (Length(Meaning) >= 1) and (Meaning[Length(Meaning)] = 's') then begin
|
---|
443 | Meaning := Copy(Meaning, 1, Length(Meaning) - 1);
|
---|
444 | end;
|
---|
445 | if Assigned(AcronymDbContent.SearchAcronym(Acronym, Meaning)) then
|
---|
446 | ReportItems.AddNew(Format(SDuplicateAcronymContent, [Acronym, Meaning]), Point(0, 0), rtWarning)
|
---|
447 | else AcronymDbContent.AddAcronym(Acronym, Meaning);
|
---|
448 | end;
|
---|
449 | end else
|
---|
450 | // No acronym inside parenthesis, continue with parsing inside
|
---|
451 | Index := StartIndex + 1;
|
---|
452 | State := stNone;
|
---|
453 | end else begin
|
---|
454 | Acronym := Acronym + Text[Index];
|
---|
455 | end;
|
---|
456 | end else begin
|
---|
457 | if Text[Index] = '(' then begin
|
---|
458 | State := stAcronymDefinition;
|
---|
459 | Acronym := '';
|
---|
460 | StartIndex := Index;
|
---|
461 | end else
|
---|
462 | if IsUppercaseAlpha(Text[Index]) then begin
|
---|
463 | State := stAcronymUsage;
|
---|
464 | Acronym := Text[Index];
|
---|
465 | if (Index - 1) >= 1 then AcronymCharBefore := Text[Index - 1]
|
---|
466 | else AcronymCharBefore := ' ';
|
---|
467 | end;
|
---|
468 | end;
|
---|
469 | Inc(Index);
|
---|
470 | until Index > Length(Text);
|
---|
471 | Lines.Free;
|
---|
472 | end;
|
---|
473 |
|
---|
474 | function TFormCheck.AllowedSideChar(Before, After: Char): Boolean;
|
---|
475 | begin
|
---|
476 | Result := ((Before = ' ') or (Before = #10) or (Before = #13) or (Before = ',') or
|
---|
477 | (Before = ';') or (Before = '(') or (Before = ')'))
|
---|
478 | and ((After = ' ') or (After = #10) or (After = #13) or (After = ',') or
|
---|
479 | (After = '.') or (After = ';') or (After = '(') or (After = ')'));
|
---|
480 | end;
|
---|
481 |
|
---|
482 | function TFormCheck.ParseMeaning(Acronym, Text: string; StartIndex: Integer;
|
---|
483 | out Meaning: string; DashSeparator: Boolean): Boolean;
|
---|
484 | var
|
---|
485 | StartIndex2: Integer;
|
---|
486 | StartIndex3: Integer;
|
---|
487 | StartIndex4: Integer;
|
---|
488 | LetterIndex: Integer;
|
---|
489 | OneWord: string;
|
---|
490 | WordLetterIndex: Integer;
|
---|
491 | WordCount: Integer;
|
---|
492 | WordCountWrong: Integer;
|
---|
493 | begin
|
---|
494 | Result := True;
|
---|
495 | Meaning := '';
|
---|
496 | StartIndex2 := StartIndex;
|
---|
497 | LetterIndex := Length(Acronym);
|
---|
498 | WordCount := 0;
|
---|
499 | WordCountWrong := 0;
|
---|
500 | while Length(Acronym) > 0 do begin
|
---|
501 | StartIndex3 := PosFromIndexReverse(' ', Text, StartIndex2);
|
---|
502 | if DashSeparator then begin
|
---|
503 | StartIndex4 := PosFromIndexReverse('-', Text, StartIndex2);
|
---|
504 | if StartIndex4 > StartIndex3 then StartIndex3 := StartIndex4;
|
---|
505 | end;
|
---|
506 |
|
---|
507 | if StartIndex3 = 0 then Break;
|
---|
508 | OneWord := Copy(Text, StartIndex3 + 1, StartIndex2 - StartIndex3);
|
---|
509 | if OneWord = '$' then begin
|
---|
510 | // Avoid parsing Bash variables
|
---|
511 | Result := False;
|
---|
512 | Exit;
|
---|
513 | end;
|
---|
514 | if Trim(OneWord) = '' then begin
|
---|
515 | StartIndex2 := StartIndex3 - 1;
|
---|
516 | Continue;
|
---|
517 | end;
|
---|
518 | // Is first letter capital?
|
---|
519 | if (Length(OneWord) > 0) and IsAlpha(OneWord[1]) then begin
|
---|
520 | WordLetterIndex := PosFromIndexReverse(LowerCase(OneWord[1]), LowerCase(Copy(Acronym, 1, LetterIndex)), LetterIndex);
|
---|
521 | if WordLetterIndex > 0 then begin
|
---|
522 | // First letter was found in acronym
|
---|
523 | if WordLetterIndex <= LetterIndex then begin
|
---|
524 | if not WordContainsLetters(LowerCase(OneWord), LowerCase(Copy(Acronym, WordLetterIndex, LetterIndex - WordLetterIndex + 1))) then begin
|
---|
525 | Result := False;
|
---|
526 | Exit;
|
---|
527 | end;
|
---|
528 | LetterIndex := WordLetterIndex - 1;
|
---|
529 | end else begin
|
---|
530 | Dec(LetterIndex);
|
---|
531 | end;
|
---|
532 | WordCountWrong := 0;
|
---|
533 | end else begin
|
---|
534 | Inc(WordCountWrong);
|
---|
535 | if WordCountWrong > 1 then begin
|
---|
536 | Result := False;
|
---|
537 | Exit;
|
---|
538 | end;
|
---|
539 | end;
|
---|
540 | end else begin
|
---|
541 | Inc(WordCountWrong);
|
---|
542 | if WordCountWrong > 1 then begin
|
---|
543 | Result := False;
|
---|
544 | Exit;
|
---|
545 | end;
|
---|
546 | end;
|
---|
547 | StartIndex2 := StartIndex3 - 1;
|
---|
548 | if LetterIndex < 1 then Break;
|
---|
549 | Inc(WordCount);
|
---|
550 | if WordCount > 2 * Length(Acronym) then begin
|
---|
551 | // False acronym in braces with too much words
|
---|
552 | Result := False;
|
---|
553 | Exit;
|
---|
554 | end;
|
---|
555 | end;
|
---|
556 | Meaning := Trim(Copy(Text, StartIndex2 + 1, StartIndex - StartIndex2));
|
---|
557 | end;
|
---|
558 |
|
---|
559 | function TFormCheck.IsUppercaseAlpha(Text: string): Boolean;
|
---|
560 | var
|
---|
561 | I: Integer;
|
---|
562 | begin
|
---|
563 | I := 1;
|
---|
564 | Result := True;
|
---|
565 | while (I <= Length(Text)) do begin
|
---|
566 | if not (Text[I] in ['A'..'Z']) then begin
|
---|
567 | Result := False;
|
---|
568 | Break;
|
---|
569 | end;
|
---|
570 | Inc(I);
|
---|
571 | end;
|
---|
572 | end;
|
---|
573 |
|
---|
574 | function TFormCheck.IsLowercaseAlpha(Text: string): Boolean;
|
---|
575 | var
|
---|
576 | I: Integer;
|
---|
577 | begin
|
---|
578 | I := 1;
|
---|
579 | Result := True;
|
---|
580 | while (I <= Length(Text)) do begin
|
---|
581 | if not (Text[I] in ['a'..'z']) then begin
|
---|
582 | Result := False;
|
---|
583 | Break;
|
---|
584 | end;
|
---|
585 | Inc(I);
|
---|
586 | end;
|
---|
587 | end;
|
---|
588 |
|
---|
589 | function TFormCheck.IsAlpha(Text: string): Boolean;
|
---|
590 | var
|
---|
591 | I: Integer;
|
---|
592 | begin
|
---|
593 | I := 1;
|
---|
594 | Result := True;
|
---|
595 | while (I <= Length(Text)) do begin
|
---|
596 | if not (Text[I] in ['A'..'Z']) and not (Text[I] in ['a'..'z']) then begin
|
---|
597 | Result := False;
|
---|
598 | Break;
|
---|
599 | end;
|
---|
600 | Inc(I);
|
---|
601 | end;
|
---|
602 | end;
|
---|
603 |
|
---|
604 | function TFormCheck.IsAcronym(Text: string): Boolean;
|
---|
605 | const
|
---|
606 | MinAcronymLength = 2;
|
---|
607 | begin
|
---|
608 | Result := (Length(Text) >= MinAcronymLength) and IsUppercaseAlpha(Text);
|
---|
609 | end;
|
---|
610 |
|
---|
611 | function TFormCheck.IsDigit(Text: Char): Boolean;
|
---|
612 | begin
|
---|
613 | Result := Text in ['0'..'9'];
|
---|
614 | end;
|
---|
615 |
|
---|
616 | procedure TFormCheck.ReportDifferencies;
|
---|
617 | var
|
---|
618 | I: Integer;
|
---|
619 | J: Integer;
|
---|
620 | Acronym: TAcronym;
|
---|
621 | Acronym2: TAcronym;
|
---|
622 | Meaning: TAcronymMeaning;
|
---|
623 | Meaning2: TAcronymMeaning;
|
---|
624 | begin
|
---|
625 | // In content but not in summary
|
---|
626 | for I := 0 to AcronymDbContent.Acronyms.Count - 1 do begin
|
---|
627 | Acronym := TAcronym(AcronymDbContent.Acronyms[I]);
|
---|
628 | if Acronym.Meanings.Count > 1 then
|
---|
629 | ReportItems.AddNew(Format(SAcronymContentMultipleMeanings, [Acronym.Name,
|
---|
630 | Acronym.Meanings.GetNames]), Point(0, 0), rtWarning);
|
---|
631 | Acronym2 := AcronymDbSummary.Acronyms.SearchByName(Acronym.Name);
|
---|
632 | if not Assigned(Acronym2) then
|
---|
633 | for J := 0 to Acronym.Meanings.Count - 1 do begin
|
---|
634 | Meaning := TAcronymMeaning(Acronym.Meanings[J]);
|
---|
635 | if not Assigned(AcronymDbSummary.SearchAcronym(Acronym.Name, Meaning.Name, [sfCaseInsensitive])) then
|
---|
636 | ReportItems.AddNew(Format(SMissingAcronymContent, [Acronym.Name, Meaning.Name]), Point(0, 0), rtWarning);
|
---|
637 | end;
|
---|
638 | end;
|
---|
639 |
|
---|
640 | // In summary but not in content
|
---|
641 | for I := 0 to AcronymDbSummary.Acronyms.Count - 1 do begin
|
---|
642 | Acronym := TAcronym(AcronymDbSummary.Acronyms[I]);
|
---|
643 | if Acronym.Meanings.Count > 1 then
|
---|
644 | ReportItems.AddNew(Format(SAcronymSummaryMultipleMeanings, [Acronym.Name, Acronym.Meanings.GetNames]), Point(0, 0), rtWarning);
|
---|
645 | Acronym2 := AcronymDbContent.Acronyms.SearchByName(Acronym.Name);
|
---|
646 | if not Assigned(Acronym2) then
|
---|
647 | for J := 0 to Acronym.Meanings.Count - 1 do begin
|
---|
648 | Meaning := TAcronymMeaning(Acronym.Meanings[J]);
|
---|
649 | if not Assigned(AcronymDbContent.SearchAcronym(Acronym.Name, Meaning.Name, [sfCaseInsensitive])) then
|
---|
650 | ReportItems.AddNew(Format(SMissingAcronymSummary, [Acronym.Name, Meaning.Name]), Point(0, 0), rtWarning);
|
---|
651 | end;
|
---|
652 | end;
|
---|
653 |
|
---|
654 | // With different meaning
|
---|
655 | for I := 0 to AcronymDbSummary.Acronyms.Count - 1 do begin
|
---|
656 | Acronym := TAcronym(AcronymDbSummary.Acronyms[I]);
|
---|
657 | Acronym2 := AcronymDbContent.Acronyms.SearchByName(Acronym.Name);
|
---|
658 | if Assigned(Acronym2) then begin
|
---|
659 | if (Acronym.Meanings.Count = 1) and (Acronym2.Meanings.Count = 1) then begin
|
---|
660 | Meaning := TAcronymMeaning(Acronym.Meanings[0]);
|
---|
661 | Meaning2 := TAcronymMeaning(Acronym2.Meanings[0]);
|
---|
662 | if not StringEqual(Meaning.Name, Meaning2.Name) then
|
---|
663 | ReportItems.AddNew(Format(SAcronymWithDifferentMeaning, [Acronym.Name, Meaning2.Name, Meaning.Name]), Point(0, 0), rtWarning);
|
---|
664 | end else
|
---|
665 | ReportItems.AddNew(Format(SAcronymWithDifferentMeaningCount, [Acronym.Name, Acronym2.Meanings.Count, Acronym.Meanings.Count]), Point(0, 0), rtWarning);
|
---|
666 | end;
|
---|
667 | end;
|
---|
668 | end;
|
---|
669 |
|
---|
670 | function TFormCheck.WordContainsLetters(Text, Letters: string): Boolean;
|
---|
671 | var
|
---|
672 | I: Integer;
|
---|
673 | LetterIndex: Integer;
|
---|
674 | begin
|
---|
675 | Result := True;
|
---|
676 | for I := 1 to Length(Letters) do begin
|
---|
677 | LetterIndex := Pos(Letters[I], Text);
|
---|
678 | if LetterIndex > 0 then begin
|
---|
679 | Text := Copy(Text, LetterIndex + 1, Length(Text));
|
---|
680 | end else begin
|
---|
681 | Result := False;
|
---|
682 | Break;
|
---|
683 | end;
|
---|
684 | end;
|
---|
685 | end;
|
---|
686 |
|
---|
687 | function TFormCheck.StringEqual(Text1, Text2: string): Boolean;
|
---|
688 | begin
|
---|
689 | if CheckBoxCaseSensitive.Checked then Result := Text1 = Text2
|
---|
690 | else Result := LowerCase(Text1) = LowerCase(Text2);
|
---|
691 | end;
|
---|
692 |
|
---|
693 | procedure TFormCheck.ReloadReport;
|
---|
694 | begin
|
---|
695 | ListViewReport.Items.Count := ReportItems.Count;
|
---|
696 | ListViewReport.Refresh;
|
---|
697 | end;
|
---|
698 |
|
---|
699 | procedure TFormCheck.UpdateInterface;
|
---|
700 | begin
|
---|
701 | LabelAcronymCountContent.Caption := SAcronymCountContent + ' ' + IntToStr(AcronymDbContent.GetMeaningsCount);
|
---|
702 | LabelAcronymCountSummary.Caption := SAcronymCountSummary + ' ' + IntToStr(AcronymDbSummary.GetMeaningsCount);
|
---|
703 | end;
|
---|
704 |
|
---|
705 | procedure TFormCheck.LoadConfig(RegistryContext: TRegistryContext);
|
---|
706 | begin
|
---|
707 | with TRegistryEx.Create do
|
---|
708 | try
|
---|
709 | RootKey := RegistryContext.RootKey;
|
---|
710 | OpenKey(RegistryContext.Key, True);
|
---|
711 | EditSummaryStart.Text := ReadStringWithDefault('SummaryStart', 'ACRONYMS AND ABBREVIATIONS');
|
---|
712 | EditSummaryEnd.Text := ReadStringWithDefault('SummaryEnd', 'Appendix');
|
---|
713 | LastDocumentFileName := ReadStringWithDefault('LastDocumentFileName', '');
|
---|
714 | CheckBoxCaseSensitive.Checked := ReadBoolWithDefault('CaseSensitiveComparison', False);
|
---|
715 | finally
|
---|
716 | Free;
|
---|
717 | end;
|
---|
718 | end;
|
---|
719 |
|
---|
720 | procedure TFormCheck.SaveConfig(RegistryContext: TRegistryContext);
|
---|
721 | begin
|
---|
722 | with TRegistryEx.Create do
|
---|
723 | try
|
---|
724 | RootKey := RegistryContext.RootKey;
|
---|
725 | OpenKey(RegistryContext.Key, True);
|
---|
726 | WriteString('SummaryStart', EditSummaryStart.Text);
|
---|
727 | WriteString('SummaryEnd', EditSummaryEnd.Text);
|
---|
728 | WriteString('LastDocumentFileName', LastDocumentFileName);
|
---|
729 | WriteBool('CaseSensitiveComparison', CheckBoxCaseSensitive.Checked);
|
---|
730 | finally
|
---|
731 | Free;
|
---|
732 | end;
|
---|
733 | end;
|
---|
734 |
|
---|
735 | end.
|
---|
736 |
|
---|