root/trunk/Units/unit_Templater.pas
| 431 | 434 | ||
|---|---|---|---|
1 | { ****************************************************************************** } | 1 | (* ***************************************************************************** |
2 | { } | 2 | * |
3 | { MyHomeLib } | 3 | * MyHomeLib |
4 | { } | 4 | * |
5 | { Version 1 } | 5 | * Класс работы с шаблонами
* |
6 | { 31.01.2010 } | 6 | * Version 1.0 |
7 | { Copyright (c) Matvienko Sergei matv84@mail.ru } | 7 | * 31.01.2010 |
8 | { } | 8 | * Copyright (c) Aleksey Penkov alex.penkov@gmail.com |
9 | { Класс работы с шаблонами } | 9 | * Author Matvienko Sergei matv84@mail.ru |
10 | { ****************************************************************************** } | 10 | * |
11 | ****************************************************************************** *) | ||
11 | 12 | ||
12 | unit unit_Templater; | 13 | unit unit_Templater; |
13 | 14 | ||
... | ... | ||
25 | 27 | ||
26 | TTemplater = class | 28 | TTemplater = class |
27 | private | 29 | private |
28 | Template: string; | 30 | FTemplate: string; |
29 | ParsedString: string; | 31 | FParsedString: string; |
30 | BlocksMap: array of TElement; | 32 | FBlocksMap: array of TElement; |
31 | public | 33 | public |
32 | constructor Create; | 34 | constructor Create; |
33 | function ValidateTemplate(Template: string): TErrorType; | 35 | function ValidateTemplate(Template: string): TErrorType; |
34 | function SetTemplate(Template: String): TErrorType; | 36 | function SetTemplate(Template: string): TErrorType; |
35 | procedure ParseTemplate(ACollection: TDMCollection); | 37 | procedure ParseTemplate(ACollection: TDMCollection); |
36 | function GetParsedString: string; | 38 | function GetParsedString: string; |
37 | end; | 39 | end; |
38 | 40 | ||
39 | implementation | 41 | implementation |
40 | 42 | ||
41 | uses SysUtils, unit_Globals, unit_Consts; | 43 | uses |
44 | SysUtils, unit_Globals, unit_Consts; | ||
42 | 45 | ||
43 | constructor TTemplater.Create; | 46 | constructor TTemplater.Create; |
44 | begin | 47 | begin |
45 | inherited; | 48 | inherited; |
46 | ParsedString := ''; | 49 | FParsedString := ''; |
47 | Template := ''; | 50 | FTemplate := ''; |
48 | end; | 51 | end; |
49 | 52 | ||
50 | function TTemplater.ValidateTemplate(Template: string): TErrorType; | 53 | function TTemplater.ValidateTemplate(Template: string): TErrorType; |
51 | const | 54 | const |
52 | mask_elements: array [1 .. 8] of string = ('f', 't', 's', 'n', 'id', 'g', | 55 | mask_elements: array [1 .. 8] of string = ('f', 't', 's', 'n', 'id', 'g', 'fl', 'rg'); |
53 | 'fl', 'rg'); | ||
54 | var | 56 | var |
55 | stack: array of TElement; | 57 | stack: array of TElement; |
56 | h, k, i, j, StackPos, ElementPos, ColElements, last_char, | 58 | h, k, i, j, StackPos, ElementPos, ColElements, last_char, last_col_elements: integer; |
57 | last_col_elements: integer; | ||
58 | bol, TemplEnd: boolean; | 59 | bol, TemplEnd: boolean; |
59 | TemplatePart: string; | 60 | TemplatePart: string; |
60 | begin | 61 | begin |
61 | // Поправка на количество частей пути в карту элементов и блоков (используется при разборе путей) | 62 | // Поправка на количество частей пути в карту элементов и блоков (используется при разборе путей) |
62 | last_col_elements := 0; | 63 | last_col_elements := 0; |
63 | last_char := 0; | 64 | last_char := 0; |
65 | |||
64 | // Определение количества элементов в шаблоне | 66 | // Определение количества элементов в шаблоне |
65 | ColElements := 0; | 67 | ColElements := 0; |
66 | for i := 1 to Length(Template) do | 68 | for i := 1 to Length(Template) do |
67 | if Template[i] = '%' then | 69 | if Template[i] = '%' then |
68 | inc(ColElements); | 70 | Inc(ColElements); |
71 | |||
69 | // Установка необходимой размерности и инициализация массивов SetLength(stack, ColElements); | 72 | // Установка необходимой размерности и инициализация массивов SetLength(stack, ColElements); |
70 | SetLength(BlocksMap, ColElements); | 73 | SetLength(FBlocksMap, ColElements); |
71 | for i := 0 to ColElements - 1 do | 74 | for i := 0 to ColElements - 1 do |
72 | begin | 75 | begin |
73 | stack[i].name := ''; | 76 | stack[i].name := ''; |
74 | BlocksMap[i].name := ''; | 77 | FBlocksMap[i].name := ''; |
75 | end; | 78 | end; |
79 | |||
76 | TemplEnd := false; | 80 | TemplEnd := false; |
77 | k := 1; | 81 | k := 1; |
78 | while not(TemplEnd) do | 82 | while not(TemplEnd) do |
... | ... | ||
85 | while (not(Template[k] in ['/', '\'])) and (k <= Length(Template)) do | 89 | while (not(Template[k] in ['/', '\'])) and (k <= Length(Template)) do |
86 | begin | 90 | begin |
87 | TemplatePart := TemplatePart + Template[k]; | 91 | TemplatePart := TemplatePart + Template[k]; |
88 | inc(k); | 92 | Inc(k); |
89 | end; | 93 | end; |
90 | inc(k); | 94 | Inc(k); |
91 | // Если больше нет элементов пути, то итеррация крайняя | 95 | // Если больше нет элементов пути, то итеррация крайняя |
92 | if k > Length(Template) then | 96 | if k > Length(Template) then |
93 | TemplEnd := true; | 97 | TemplEnd := true; |
... | ... | ||
100 | // Поиск открывающей скобки блока элемента
if TemplatePart[i] = '[' then | 104 | // Поиск открывающей скобки блока элемента
if TemplatePart[i] = '[' then |
101 | begin | 105 | begin |
102 | inc(StackPos); | 106 | Inc(StackPos); |
103 | stack[StackPos].BegBlock := i; | 107 | stack[StackPos].BegBlock := i; |
104 | stack[StackPos].name := ''; | 108 | stack[StackPos].name := ''; |
105 | end; | 109 | end; |
... | ... | ||
112 | if (stack[StackPos].name <> '') and (StackPos > 0) then | 116 | if (stack[StackPos].name <> '') and (StackPos > 0) then |
113 | begin | 117 | begin |
114 | Result := ErTemplate; // В блоке не может быть более одного элемента
exit; | 118 | Result := ErTemplate; // В блоке не может быть более одного элемента
exit; |
119 | Exit; | ||
115 | end; | 120 | end; |
116 | 121 | ||
117 | // Выделяем название элемента
inc(i); | 122 | // Выделяем название элемента
inc(i); |
123 | Inc(i); | ||
118 | stack[StackPos].name := ''; | 124 | stack[StackPos].name := ''; |
119 | while CharInSet(TemplatePart[i], ['a' .. 'z', 'A' .. 'Z']) do | 125 | while CharInSet(TemplatePart[i], ['a' .. 'z', 'A' .. 'Z']) do |
120 | begin | 126 | begin |
121 | stack[StackPos].name := stack[StackPos].name + TemplatePart[i]; | 127 | stack[StackPos].name := stack[StackPos].name + TemplatePart[i]; |
122 | inc(i); | 128 | Inc(i); |
123 | end; | 129 | end; |
124 | dec(i); | 130 | Dec(i); |
125 | 131 | ||
126 | // Добавляем элемент в общий список элементов | 132 | // Добавляем элемент в общий список элементов |
127 | if StackPos = 0 then | 133 | if StackPos = 0 then |
128 | begin | 134 | begin |
129 | BlocksMap[ElementPos + last_col_elements].name := stack[StackPos] | 135 | FBlocksMap[ElementPos + last_col_elements].name := stack[StackPos].name; |
130 | .name; | 136 | FBlocksMap[ElementPos + last_col_elements].BegBlock := 0; |
131 | BlocksMap[ElementPos + last_col_elements].BegBlock := 0; | 137 | FBlocksMap[ElementPos + last_col_elements].EndBlock := 0; |
132 | BlocksMap[ElementPos + last_col_elements].EndBlock := 0; | 138 | Inc(ElementPos); |
133 | inc(ElementPos); | ||
134 | end; | 139 | end; |
135 | |||
136 | end; | 140 | end; |
137 | 141 | ||
138 | // Поиск окончания блока элемента | 142 | // Поиск окончания блока элемента |
... | ... | ||
145 | if (stack[StackPos].name = '') or (StackPos <= 0) then | 147 | if (stack[StackPos].name = '') or (StackPos <= 0) then |
146 | begin | 148 | begin |
147 | Result := ErBlocks; // Проверьте соответствие открывающих и закрывающих скобок блоков элементов | 149 | Result := ErBlocks; // Проверьте соответствие открывающих и закрывающих скобок блоков элементов |
148 | exit; | 150 | Exit; |
149 | end; | 151 | end; |
150 | stack[StackPos].EndBlock := i; | 152 | stack[StackPos].EndBlock := i; |
151 | 153 | ||
152 | // Добавляем элемент в общий список элементов | 154 | // Добавляем элемент в общий список элементов |
153 | BlocksMap[ElementPos + last_col_elements].name := stack[StackPos].name; | 155 | FBlocksMap[ElementPos + last_col_elements].name := stack[StackPos].name; |
154 | BlocksMap[ElementPos + last_col_elements].BegBlock := stack[StackPos] | 156 | FBlocksMap[ElementPos + last_col_elements].BegBlock := stack[StackPos].BegBlock + last_char; |
155 | .BegBlock + last_char; | 157 | FBlocksMap[ElementPos + last_col_elements].EndBlock := stack[StackPos].EndBlock + last_char; |
156 | BlocksMap[ElementPos + last_col_elements].EndBlock := stack[StackPos] | 158 | Inc(ElementPos); |
157 | .EndBlock + last_char; | ||
158 | inc(ElementPos); | ||
159 | 159 | ||
160 | dec(StackPos); | 160 | Dec(StackPos); |
161 | end; | 161 | end; |
162 | 162 | ||
163 | // Переход к очередному символу в шаблоне | 163 | // Переход к очередному символу в шаблоне |
164 | inc(i); | 164 | Inc(i); |
165 | end; | 165 | end; |
166 | 166 | ||
167 | // Имеются незакрытые скобки блоков | ||
168 | if StackPos > 0 then | ||
169 | begin | ||
170 | Result := ErBlocks; // Проверьте соответствие открывающих и закрывающих скобок блоков элементов | ||
171 | Exit; | ||
172 | end; | ||
173 | |||
167 | // Проверка всех элементов на правильность написания | 174 | // Проверка всех элементов на правильность написания |
168 | for h := Low(BlocksMap) to High(BlocksMap) do | 175 | for h := Low(FBlocksMap) to High(FBlocksMap) do |
169 | begin | 176 | begin |
170 | if BlocksMap[h].name <> '' then | 177 | if FBlocksMap[h].name <> '' then |
171 | begin | 178 | begin |
172 | bol := false; | 179 | bol := False; |
173 | for j := 1 to High(mask_elements) do | 180 | for j := 1 to High(mask_elements) do |
174 | if BlocksMap[h].name = mask_elements[j] then | 181 | if FBlocksMap[h].name = mask_elements[j] then |
175 | bol := true; | 182 | begin |
183 | bol := True; | ||
184 | Break; | ||
185 | end; | ||
176 | 186 | ||
177 | if not(bol) then | 187 | if not(bol) then |
178 | break; | 188 | Break; |
179 | end; | 189 | end; |
180 | end; | 190 | end; |
181 | 191 | ||
182 | // Имеются незакрытые скобки блоков | ||
183 | if StackPos > 0 then | ||
184 | begin | ||
185 | Result := ErBlocks; // Проверьте соответствие открывающих и закрывающих скобок блоков элементов
| ||
186 | exit; | ||
187 | end; | ||
188 | // Имеются неверние элементы шаблона | 192 | // Имеются неверние элементы шаблона |
189 | if not(bol) then | 193 | if not(bol) then |
190 | begin | 194 | begin |
191 | Result := ErElements; // Неверные элементы шаблона | 195 | Result := ErElements; // Неверные элементы шаблона |
192 | exit; | 196 | Exit; |
193 | end; | 197 | end; |
194 | 198 | ||
195 | inc(last_col_elements, ElementPos); | 199 | Inc(last_col_elements, ElementPos); |
196 | 200 | ||
197 | // Поправка на количество символов с начала строки шаблона в
// карту элементов и блоков (используется при разборе путей) | 201 | // Поправка на количество символов с начала строки шаблона в
// карту элементов и блоков (используется при разборе путей) |
198 | last_char := last_char + k - 1; | 202 | last_char := last_char + k - 1; |
199 | 203 | ||
200 | // Переход к очередному символу в шаблоне с целью обработки следующей части пути к файлу
inc(i); | 204 | // Переход к очередному символу в шаблоне с целью обработки следующей части пути к файлу
inc(i); |
205 | Inc(i); | ||
201 | end; | 206 | end; |
202 | 207 | ||
203 | // Если замечаний нет, то шаблон валиден | 208 | // Если замечаний нет, то шаблон валиден |
... | ... | ||
210 | begin | 214 | begin |
211 | Result := ValidateTemplate(Template); | 215 | Result := ValidateTemplate(Template); |
212 | if Result = ErFine then | 216 | if Result = ErFine then |
213 | Self.Template := Template; | 217 | FTemplate := Template; |
214 | end; | 218 | end; |
215 | 219 | ||
216 | procedure TTemplater.ParseTemplate(ACollection: TDMCollection); | 220 | procedure TTemplater.ParseTemplate(ACollection: TDMCollection); |
... | ... | ||
226 | i, j: integer; | 230 | i, j: integer; |
227 | R: TBookRecord; | 231 | R: TBookRecord; |
228 | begin | 232 | begin |
229 | ParsedString := Self.Template; | 233 | FParsedString := FTemplate; |
230 | 234 | ||
231 | // Получение текущей книги ACollection.GetCurrentBook(R); | 235 | // Получение текущей книги ACollection.GetCurrentBook(R); |
... | ... | ||
249 | 253 | ||
250 | MaskElements[4].templ := 'f'; | 254 | MaskElements[4].templ := 'f'; |
251 | AuthorName := ''; | 255 | AuthorName := ''; |
252 | for i := low(R.Authors) to high(R.Authors) do | 256 | for i := Low(R.Authors) to High(R.Authors) do |
253 | begin | 257 | begin |
254 | LastName := R.Authors[i].FLastName; | 258 | LastName := R.Authors[i].FLastName; |
255 | if R.Authors[i].FFirstName <> '' then | 259 | if R.Authors[i].FFirstName <> '' then |
... | ... | ||
257 | if R.Authors[i].FMiddleName <> '' then | 261 | if R.Authors[i].FMiddleName <> '' then |
258 | MiddleName := ' ' + R.Authors[i].FMiddleName[1] + '.'; | 262 | MiddleName := ' ' + R.Authors[i].FMiddleName[1] + '.'; |
259 | AuthorName := AuthorName + LastName + FirstName + MiddleName; | 263 | AuthorName := AuthorName + LastName + FirstName + MiddleName; |
260 | if i < high(R.Authors) then | 264 | if i < High(R.Authors) then |
261 | AuthorName := AuthorName + ', '; | 265 | AuthorName := AuthorName + ', '; |
262 | end; | 266 | end; |
263 | MaskElements[4].value := AuthorName; | 267 | MaskElements[4].value := AuthorName; |
... | ... | ||
274 | end; | 278 | end; |
275 | 279 | ||
276 | MaskElements[7].templ := 'fl'; | 280 | MaskElements[7].templ := 'fl'; |
277 | MaskElements[7].value := R.Authors[ low(R.Authors)].FLastName[1]; | 281 | MaskElements[7].value := R.Authors[Low(R.Authors)].FLastName[1]; |
278 | 282 | ||
279 | MaskElements[8].templ := 'rg'; | 283 | MaskElements[8].templ := 'rg'; |
280 | MaskElements[8].value := ACollection.GetRootGenre(R.LibID); | 284 | MaskElements[8].value := ACollection.GetRootGenre(R.LibID); |
281 | 285 | ||
282 | // Цикл удаления "пустых" блоков | 286 | // Цикл удаления "пустых" блоков |
283 | for i := Low(MaskElements) to High(MaskElements) do | 287 | for i := Low(MaskElements) to High(MaskElements) do |
284 | for j := Low(BlocksMap) to High(BlocksMap) do | 288 | for j := Low(FBlocksMap) to High(FBlocksMap) do |
285 | if (MaskElements[i].templ = BlocksMap[j].name) and | 289 | if (MaskElements[i].templ = FBlocksMap[j].name) and (MaskElements[i].value = '') then |
286 | (MaskElements[i].value = '') then | 290 | if (FBlocksMap[j].BegBlock <> 0) and (FBlocksMap[j].EndBlock <> 0) then |
287 | if (BlocksMap[j].BegBlock <> 0) and (BlocksMap[j].EndBlock <> 0) then | ||
288 | begin | 291 | begin |
289 | Delete(ParsedString, BlocksMap[j].BegBlock, | 292 | Delete(FParsedString, FBlocksMap[j].BegBlock, FBlocksMap[j].EndBlock - FBlocksMap[j].BegBlock + 1); |
290 | BlocksMap[j].EndBlock - BlocksMap[j].BegBlock + 1); | ||
291 | // Здесь ещё продумаю вариант удаления записей о вложенных элементах без валидации | 293 | // Здесь ещё продумаю вариант удаления записей о вложенных элементах без валидации |
292 | ValidateTemplate(ParsedString); | 294 | ValidateTemplate(FParsedString); |
293 | end; | 295 | end; |
294 | 296 | ||
295 | // Цикл удаления квадратных скобок | 297 | // Цикл удаления квадратных скобок |
296 | for i := Length(ParsedString) downto 1 do | 298 | for i := Length(FParsedString) downto 1 do |
297 | if CharInSet(ParsedString[i], ['[', ']']) then | 299 | if CharInSet(FParsedString[i], ['[', ']']) then |
298 | Delete(ParsedString, i, 1); | 300 | Delete(FParsedString, i, 1); |
299 | 301 | ||
300 | // Цикл замены элементов шаблона их значениями | 302 | // Цикл замены элементов шаблона их значениями |
301 | for i := 1 to mask_elements do | 303 | for i := 1 to mask_elements do |
302 | StrReplace('%' + MaskElements[i].templ, MaskElements[i].value, | 304 | StrReplace('%' + MaskElements[i].templ, MaskElements[i].value, FParsedString); |
303 | ParsedString); | ||
304 | end; | 305 | end; |
305 | 306 | ||
306 | function TTemplater.GetParsedString: string; | 307 | function TTemplater.GetParsedString: string; |
307 | begin | 308 | begin |
308 | Result := ParsedString; | 309 | Result := FParsedString; |
309 | end; | 310 | end; |
310 | 311 | ||
311 | end. | 312 | end. |
Download diff