-
Notifications
You must be signed in to change notification settings - Fork 0
/
task_6.php
471 lines (380 loc) · 46.1 KB
/
task_6.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
<?php
/* -----
6. Кодинг
В переменной $a лежит текст новости с HTML-разметкой (ссылки, жирность, списки…). В переменной $link лежит ссылка на страницу с полным текстом этой новости.
Нужно в переменную $b записать сокращенный текст новости по правилам:
- обрезать до 180 символов;
- приписать многоточие;
- последние 2 слова и многоточие сделать ссылкой на полный текст новости;
- HTML-разметку удалять нельзя.
Результат: ссылка на репозиторий с кодом и ваши комментарии.
----- */
// * Для наглядности вместо переменной $a будет использована переменная $newsText
// В качестве текста новости в переменную $newsText записано описание данной задачи с добавлением некоторой разметки (жирность, списки и т. п.)
$newsText = '<div class="task-page__description"><p>В переменной <strong>$a</strong> лежит текст новости с HTML-разметкой (ссылки, жирность, списки…). В переменной <strong>$link</strong> лежит ссылка на страницу с полным текстом этой новости.</p><p>Нужно в переменную <strong>$b</strong> записать сокращенный текст новости по правилам:</p><ul><li>обрезать до 180 символов;</li><li>приписать многоточие;</li><li>последние 2 слова и многоточие сделать ссылкой на полный текст новости,</li><li>HTML-разметку удалять нельзя.</li></ul><p>Результат: ссылка на репозиторий с кодом и ваши комментарии.</p></div>';
$link = '/news-tags.html';
// Чистим входной текст от лишних пробелов (форматируя HTML-дерево в сплошной текст)
// Это сделано на случай если в переменную был записан текст в древовидном формате
$newsText = preg_replace('/\s\s+/', '', $newsText);
// * Для наглядности вместо переменной $b будет использована переменная $shortText
$shortText = '';
// -------------------------------------------------- Решение № 1 --------------------------------------------------
/* -------------------------
!!! Сразу информирую, что решить задачу на 100% не получилось. Ниже изложены некоторые причины и пояснения.
Тезисное описание алгоритма решения.
------------------------------------
Разобьем входную строку на два массива.
* Если входная HTML-строка будет правильно структурирована (дерево тегов), значит, по идее должно получиться два массива с предполагаемым содежимым.
** Вышеуказанное примечание сделано на какой-либо непредвиденный случай. На данный момент ни один тестовый случай не выявил обратное.
Предполагается, что массив $arrTags наполнен исключительно тегами, а массив $arrText - подстроками контента.
Входная строка выше разобьётся на массивы
Array "$arrTags"
(
[0] => <div class="task-page__description">
[1] => <p>
[2] => <strong>
[3] => </strong>
... и т. д.
)
Array "$arrText"
(
[0] =>
[1] =>
[2] => В переменной
[3] => $a
[4] => лежит текст новости с HTML-разметкой (ссылки, жирность, списки…). В переменной
... и т. д.
)
При этом массив $arrText может иметь пустые элементы, которые получаются при разбиении функцией preg_split двух идущих подряд тегов.
Например, "...</strong><span>..." или "<div><p>..."
Для получения результирующего набора данных $resultArr программа циклом for будет пробегать сначала по массиву $arrText с подстроками контента,
записывая в набор только тот элемент $arrText[$i], который не пустой. В противном случае, если элемент $arrText[$i] массива $arrText пустой, программа будет
записывать в набор элемент $arrTags[$i] массива $arrTags с тем же индексом $i, на котором остановилась итерация цикла.
Последовательно записывая в результирующий набор $resultArr элементы из двух массивов, программа будет измерять и суммировать длину записываемых подстрок контента.
В двух местах тела цикла будет выполняться проверка общей длины текстового контента (без тегов). При достижении 180 символов обход массива $arrText
должен быть остановлен. При этом, в соответствии с условием задачи, исключающим удаление HTML-разметки, обход массива $arrTags и запись в результирующий
набор $resultArr оставшихся элементов $arrTags[$i] будут продолжены.
Когда будет найдена последняя подстрока, программа выполнит её разбиение на массив с помощью функции explode по пробелу, найдет предпоследнее и последнее
слова, добавит к ним тег <a href=""></a>, в атрибуте "href" которого будет указана ссылка на страницу с полным текстом новости.
Затем функцией implode по пробелу будет сформировано новое значение последней подстроки, а сама подстрока - добавлена в результирующий набор $resultArr.
Заключительным этапом программой будет выполнено преобразование результирующего набора $resultArr в строку.
------------------------- */
// Функцией preg_match_all получим массив $matches вхождений шаблона "|<[/]?[^>]+>|U" в строку $newsText
preg_match_all("|<[/]?[^>]+>|U", $newsText, $matches);
// С учетом особенностей работы функции preg_match_all получим массив, элементами которого будут только теги
$arrTags = $matches[0];
// Сформированнный функцией preg_match_all массив массивов $matches дальше не нужен, поэтому удалим его
unset($matches);
// Разбиением входной строки по тегам получим массив входящих в строку подстрок
$arrText = preg_split("|<[/]?[^>]+>|U", $newsText);
// Инициализируем переменные, которые понадобятся нам для решения данной задачи
$resultArr = array(); // Массив (результирующий набор), в который в определенном порядке будут "укладываться" теги и подстроки
$countArrTags = count($arrTags); // Количество элементов в массиве с тегами
$countArrText = count($arrText); // Количество элементов в массиве с подстроками
$generalLength = 0; // Переменная для проверки общей длины текстового контента без тегов
$countTags = 0; // Счётчик для подсчета тегов, записанных в результируюзий набор
// Запускаем цикл перебора массива $arrText с подстроками контента
for ($i = 0; $i < $countArrText; $i++) {
// Проверяем общую длину текстовой части результирующего набора, чтобы вовремя (при достижении длины 180 символов) остановить цикл
if ($generalLength == 180) {
break;
}
// Проверка массива $arrTags на наличие ключа $i нужна потому, что для определения нужного в данный момент элемента (в двух массивах)
// используется один ключ, при этом в массиве $arrTags может быть меньше элементов, чем в массиве $arrText
// Если проверку не выполнить, в подобном случае программа выдаст ошибку (обращение к несуществующему ключу).
if (array_key_exists($i, $arrTags)) {
// Проверяем элемент массива $arrText на пустоту
if (empty($arrText[$i])) {
// Если элемент пустой (подстрока отсутсвует), значит, сначала должен быть тег, поэтому в результирующий набор $resultArr помещаем
// элемент массива с тегами $arrTags с текущим значением ключа $i, а также увеличиваем счётчик тегов, помещенных в результирующий набор
array_push($resultArr, $arrTags[$i]);
$countTags++;
} else {
// В противном случае в результирующий набор должна быть записана сначала подстрока, а сразу за ней - тег (элемент массива $arrTags с таким же ключом)
// Измеряем длину подстроки и суммируем полученное значение с общей длиной текстового контента без тегов
$length = mb_strlen($arrText[$i]);
$generalLength = $generalLength + $length;
// Проверяем общую длину текстового контента без тегов
if ($generalLength >= 180) {
// Если общая длина текстового контента без тегов больше либо равна 180 символам, тогда получаем длину, на которую должна быть обрезана текущая подстрока,
// чтобы общая длина составила 180 символов, и обрезаем её
$inequality = 180 - ($generalLength - $length);
$lastSubstring = mb_substr($arrText[$i], 0, $inequality);
// ---------------------------------------------
// Здесь получаем два последних слова для оборачивания в тег <a href=""></a>
// Для этого необходимо последнюю подстроку разбить на массив слов по пробелу
$arrWords = explode(' ', $lastSubstring);
// * Примечание *
// Особенность дальнейшей реализации решения заключается в том, что последняя подстрока может содержать всего одно слово (или часть слова).
// Получить предпоследнее слово в таком случае, не перегрузив код условными конструкциями, не получится. Во всяком случае, у меня пока нет решения.
// Проверим количество слов в последней подстроке
if (count($arrWords) > 1) {
// Если больше одного, тогда последовательным применением функции array_pop получаем сначала последнее, затем предпоследнее слова и обновляем
// значение последней подстроки, обернув последние два слова в тег <a href=""></a>
$lastWordForLink = array_pop($arrWords);
$penultWordForLink = array_pop($arrWords);
// В определённой ситуации $penultWordForLink (предпоследнее) может оказаться пустой
// Так происходит в ситауции с входной строкой, указанной в переменной $newsText, когда предпоследнее и последнее слова находятся в строке
// формата "...<strong>препоследнее</strong> последнее..." или в аналогичной.
// Этого можно избежать, если дополнительно проверять первый элемент массива $arrWords на пустоту, а общее количество элементов на соответствие
// условию if (count($arrWords) > 3).
// В данном случае это не выполнено, поскольку в целом ситуация с поиском предпоследнего слова осложняется нижеследующими обстоятельствами.
// Если подстроки из массива $arrText не пропускать через функцию trim, а последняя подстрока контента будет содержать одно слово (полное или неполное),
// перед которым имеется пробел, то при формировании результирующего набора переменная $arrWords, получаемая разбиением последней подстроки по пробелу,
// будет содержать массив с двумя элементами, один из которых пустой ($penultWordForLink).
// В таком случае проверка if (count($arrWords) > 1) будет пройдена как TRUE, а в теге '<a href=""></a>' окажется пробел и последнее слово после него.
// Во избежание подобных случаев нужно пропускать каждую подстроку через функцию trim, однако это может привести к "склейке" подстрок между собой при
// дальнейшем формировании результирующей строки для вывода. Такой вариант, на мой взгляд, нежелателен.
// Поскольку пробел перед единственным (последним) словом внутри тега '<a href=""></a>' в браузере не отображается, предпоследнее и последнее слова могут
// получиться склеенными. Чтобы избежать подобные случаи, ниже была введена условная конструкция для проверки $penultWordForLink на пустоту.
if (empty($penultWordForLink)) {
// Если $penultWordForLink пустая, значит её не учитываем
$newLastSubstring = implode(' ', $arrWords) . ' ' . '<a href="' . $link . '">' . $lastWordForLink . '...</a>';
} else {
// В противном случае вписываем оба слова
$newLastSubstring = implode(' ', $arrWords) . ' ' . '<a href="' . $link . '">' . $penultWordForLink . ' ' . $lastWordForLink . '...</a>';
}
} else {
// Если в последней подстроке только одно слово, тогда предпоследнее слово можно искать в предыдущих подстроках, однако многообразие возможных
// вариаций входных строк сильно усложняет решение данной задачи известными мне инструментами (см. ниже).
// По причинам, указанным ниже, условие задачи о том, что ссылка на страницу с полным текстом новости должна содержать 2 слова, в определенных
// ситуациях не выполнится.
// Поскольку слово одно, применять функции array_pop и implode бессмысленно
// Обновляем последнюю подстроку оборачиванием её в тег <a href=""></a>
$newLastSubstring = ' ' . '<a href="' . $link . '">' . $arrWords[0] . '</a>';
// if (preg_match("|<[^>]+>|U", $resultArr[$i - 1])) {}
}
// ---------------------------------------------
// Добавляем изменённую последнюю подстроку в результирующий набор $resultArr
array_push($resultArr, $newLastSubstring);
} else {
// Если общая длина текстового контента без тегов меньше 180 символов, тогда добавляем в набор текущую подстроку полностью
array_push($resultArr, $arrText[$i]);
}
// Добавляем в результирующий набор $resultArr элемент массива $arrTags с текущим индексом и увеличиваем на единицу счётчик добавленных тегов
array_push($resultArr, $arrTags[$i]);
$countTags++;
}
}
}
// В случае если в массиве $arrTags остались теги, не добавленные в результирующий набор, добавим их в него
// Для этого надо проверить массив $arrTags на наличие ключа со значением, равным значению счётчика добавленных тегов
if (array_key_exists($countTags, $arrTags)) {
// Если ключ с таким значением в массиве имеется, значит, циклом for пробежим по оставшимся тегам и добавим их в результирующий набор
// Таким образом, условие о неудалении HTML-разметки будет выполнено
// В некоторых ситуациях в массиве $arrTags могут остаться теги, влияющие на отображение результирующего набора. Например, тег <li>, который будет добавлять
// элемент списка без содержимого, что, при соблюдении условия о неудалении HTML-разметки, приведёт к отображению маркеров элементов списка)
for ($j = $countTags; $j < $countArrTags; $j++) {
array_push($resultArr, $arrTags[$j]);
}
}
// В переменную $shortText записываем строку, полученную с помощью функции implode из результирующего набора $shortText
$shortText = implode($resultArr);
/* -------------------------
Проблемы, возникшие при реализации решения задачи:
--------------------------------------------------
В случае если последняя вошедшая в результирующий набор $resultArr подстрока контента содержит одно слово (неважно, полное или неполное), поиск предпоследнего
слова становится, на мой взгляд, весьма нелёгкой задачей.
Именно такая ситуация и произойдет, если ввести строку, присвоенную переменной $newsText.
В одном из упомянутых ниже случаев для поиска предпоследнего слова и определения места для расположения открывающего тега <a href=""> необходимо будет учесть
характер тега(-ов) между предпоследним и последним словами, то есть открывающий это тег, закрывающий или, вообще, непарный, их количество, а также количество слов
подстроки контента, в которой содержится предпоследнее слово. Объясню почему.
На выходе программа должна получить 180 символов текстового контента с двумя словами ссылкой в конце. Учитывая, что во входной строке теги могут располагаться
в самых разных конфигурациях, предпоследнее и последнее слова в строке длиной 180 символов могут располагаться на участке одной из следующих конфигураций:
1) <p>слово слово слово <strong>слов... // предпоследнее слово находится перед открывающим тегом
2) <strong>слово</strong> слов... // предпоследнее слово находится между открывающим и закрывающим тегами в подстроке длиной в одно слово
3) <strong>слово слово слово </strong> слов... // предпоследнее слово находится между открывающим и закрывающим тегами в подстроке длиной в несколько слов
4) <strong>слово</strong><em> слов...
5) <strong>слово слово слово</strong><em> слов...
6) <strong>кап<em>Ю</em>шон</strong> слов...
7) <strong>слово<em>слово</em></strong> слов...
8) <em>слово<strong>слово слово слово </strong></em> слов...
9) <strong>слово</strong>слово</em> слов...
10) и т. п.
На мой взгяд, не осложняя код избыточными условными конструкциями, можно обработать только самую простую конфигурацию № 2.
Опять-таки, именно она и попадётся, если использовать строку, присвоенную переменной $newsText. Выглядеть это будет следующим образом.
Пророграмма получает последнюю подстроку, в которой имеется только одно слово, добавляет к нему многоточие и закрывающий тег </a>. Затем циклом в обратном порядке
($i--) двигается по результирующему набору $resultArr, проверяя элементы на соответствие определенному регулярному выражению. При первой итерации программа попадёт
на закрывающий тег. При следующей итерации цикла программе попадётся текстовая подстрока, в которой содержится всего одно слово. Тогда, если входная строка содержала
синтаксически правильную HTML-разметку, при третьей итерации цикла программе должен попасться открывающий тег, закрывающая часть которого была в первой итерации.
В подобном случае третья итерация будет не нужна. Вместо этого к элементу, содержащему открывающий тег, будет приписан открывающий тег <a href="">.
Закрывающий тег </a> нужно будет расположить за многочием, приписанным к последнему слову.
Таким образом, будет получена новая конфигурация "<a href=""><strong>слово</strong> слов...</a>".
Однако подобный способ решить эту задачу будет являться универсальным лишь для двух характерных случаев входных данных:
- когда предпоследнее и последнее слово находится в одной подстроке (тогда эта описанная в предыдущем абзаце часть кода не будет задействована);
- когда предпоследнее и последнее слово находятся в разных подстроках, но конфигурация их расположения соответствует конфигурации № 2.
Другой пример: во входной строке программе попалась конфигурация № 3 (одна их самых простых из представленных).
Тогда соблюсти все условия задачи (длина - 180 символов, 2 последних слова - ссылкой, сохранение HTML-разметки), не нарушив правила написания HTML-разметки
не получится, поскольку для выполнения двух последних слов ссылкой открывающий тег <a href=""> придётся ставить "внахлест" с уже имеющимися тегами
(в конфигурации № 3 - с тегами <strong>), что является некорректным действием и сделает HTML-разметку невалидной.
Конфигурация № 6 - это вообще уникальный случай!
Допустим, программе попадается статья, в которой написано, что филологи решили, что слово "капюшон" отныне пишется через "Ё".
Верстальщики для того, чтобы подчеркнуть необходимые тезисы статьи, придумали конфигурацию, аналогичную конфигурации № 6, а 180-й символ - это буква "т" в слове
"пишется", и вот мы уже имеем строку "<strong>капюш<em>Ё</em>н</strong> пишет..."
При обработке этого участка строки текстовый контент будет представлен четырьмя подстроками, каждая из которых будет интерпретирована программой как отдельное слово.
Этот факт сильно осложняет решение подобной задачи известными мне способами.
Вводить на каждый такой случай условные конструкции, счётчики тегов и прочие инструменты для проверки элементов результирующего набора - плохой выбор.
Честно говоря, не представляю, каким образом можно решить эту задачу, соблюдая все условия задачи. Фраза "HTML-разметку удалять нельзя" в контексте данной задачи
запрещает мне и изменение её струтуры, поэтому варианты с перемещением некоторых тегов куда-либо мною не рассматривались.
Кроме того, исходя из условий задачи, непонятно, как поступать со тегами <li>, которые могут присутствовать во входной строке, но при этом останутся
без текстового содержимого в результате её обработки. Если удалять HTML-разметку нельзя, тогда в определенных обстоятельствах в результирующий вывод
будут попадать маркеры списка.
Решить задачу, соблюдая условия неприкосновенности HTML-разметки, можно будет, наверно, либо удалением маркеров списка, либо скрытием лишнего содержимого
с использованием средств CSS и/или JS.
По состоянию на сегодняшний день мой личный инструментарий не позволяет решить эту задачу с соблюдением всех заданных условий.
Задачу, в которой основным условием явлется ограничение контента с сохранением HTML-разметки, я бы решал, не аккцентируя внимание на оформлении
ссылкой именно последних двух слов.
Оформить ссылкой безо всяких проблем можно было бы только последнее слово и многоточие или какую-нибудь кнопку (например, "Читать полностью").
с целью ограничения отображаемого контента по высоте можно обратиться к средствам CSS (например, к свойству -webkit-line-clamp).
Если нужно получить ссылкой именно два последних слова, можно прибегнуть к "костыльному" методу, обернув тегами <a></a> каждое из них по отдельности.
------------------------- */
// ==================================================================================================================================================
/*
// ------------------------- Решение № 2 -------------------------
// Решение будет выглядеть следующим образом: сначала получим из входной строки массив, элементами которого будут только теги.
// Затем перебирая этот массив, будем находить начальную позицию каждого тега во входной строке, измерять его длину и, суммируя эти два значения,
// определять позицию, где текущий тег заканчивается.
// Если значение начальной позиции следующего тега равно конечной позиции предыдущего, значит, теги идут друг за другом. Если между значениями
// начальной позиции текущего тега и конечной позицией предыдущего есть разница, значит, между ними есть текст.
// Вычитая из значения начальной позиции текущего тега значение конечной позиции предыдущего, будем получать длину подстроки текстового контента
// во входной строке и использовать её в функции mb_substr.
// Значения длин вырезаемых подстрок будем складывать между собой, чтобы иметь возможность проверять общую длину текстового контента.
// В зависимости от того, равна ли общая длина текста значению 180 символов, в результирующий набор $resultArr будут добавляться либо теги и текстовый
// контент, либо только теги.
// Инициализируем переменные, которые понадобятся нам для решения данной задачи
$resultArr = array(); // Массив (результирующий набор), в который в определенном порядке будут "укладываться" теги и подстроки
$subString = ''; // Подстрока текста без тегов, которую будем получать с помощью mb_substr из входного текста
$offset = 0; // Позиция, с которой будет осуществляться поиск каждого тега во входной строке (конечная позиция предыдущего тега)
$length = 0; // Длина, которую будем указывать в качестве аргумента mb_substr для получения подстроки текста без тегов
$generalLength = 0; // Переменная для проверки общей длины текстового контента без тегов
// Циклом foreach переберем каждый тег в массиве $arrTags
foreach ($arrTags as $tag) {
// Проверяем длину текста без тегов
// Если длина текста достигла значения 180 символов или более, тогда добавляем в результирующий массив только теги
if ($generalLength >= 180) {
array_push($resultArr, $tag);
continue;
}
// Если условие выше не TRUE, тогда проходим полную итерацию
// Находим позицию текщего тега во входной строке
$strpos = mb_strpos($newsText, $tag, $offset);
// Проверяем, совпадает ли позиция текущего тега в строке с конечной позицией предыдущего тега
if ($strpos == $offset) {
// Если TRUE, то добавляем в результирующий массив только тег
array_push($resultArr, $tag);
} else {
// Если FALSE - сначала добавляем в результирующий массив строку текста без тегов, затем - текущий тег
// Для этого:
// Определяем длину текста без тегов, который надо вырезать, вычитая из позиция текущего тега конечную позицию предыдущего
// Для первого тега в строке, значение $offset долно равняться 0, если вся входная строка начинается с тега
// Однако, если во входной строке будет передан текст, в котором первый тег будет находиться где-то в середине, это решение не сработает
$length = $strpos - $offset;
// Добавляем полученное значение длины к общей длине для последующей проверки на 180 символов
$generalLength += $length;
// Проверяем длину текста без тегов
if ($generalLength >= 180) {
// Если 180 или более, тогда находим длину подстроки для добавления в массив, чтобы общая длина не превышала 180 символов
$inequality = 180 - ($generalLength - $length);
// Чистим конец строки от пробелов или других символов по маске // "\t\r\n\0\x0B,.!&"
$subString = rtrim(mb_substr($newsText, $offset, $inequality));
} else {
// Если менее 180, вырезаем подстроку из входного текста, начиная с позиции окончания предыдущего тега до начала текущего тега
$subString = mb_substr($newsText, $offset, $length);
}
// Добавляем полученную подстроку и текущий тег в результирующий массив
array_push($resultArr, $subString);
array_push($resultArr, $tag);
}
// Определяем позицию окончания текущего тега, суммируя значения его начальной позиции и длины
$offset = $strpos + mb_strlen($tag);
}
// Как только перебор массива будет окончен, у нас будет полный результирующий набор для дальнеших манипуляций.
// Код ниже по задумке должен был перебирать результирующий набор в обратном порядке для поиска последнего и предпоследнего слов, однако
// при его реализации я столкнулся с проблемами, описанными выше. Код перегружен условными конструкциями, а их вложенность не позволяет обеспечить
// читаемость кода. По этой причине от такого подхода пришлось отказаться.
// Получим счётчик для перебора массива в обратном порядке
$lastKeyResArr = count($resultArr) - 1;
// Циклом for начинаем перебирвать массив
for ($i = $lastKeyResArr; $i > 0; $i--) {
// Каждый элемент массива проверяем на соответствие регулярному выражению
if (preg_match("|<[/]?[^>]+>|U", $resultArr[$i])) {
// Если TRUE, значит, это тег - листаем дальше
continue;
} else {
// Если FALSE, значит, это текст
// Разбиваем по пробелу, чтобы получить массив слов
$arrWords = explode(' ', trim($resultArr[$i]));
// Проверяем количество элементов в полученном массиве
if (count($arrWords) > 1) {
// Если элементов более 1, значит, получим предпоследнее и последнее слова и обернём их в тег гиперссылки и прервём цикл
$lastWordForLink = array_pop($arrWords) . '...</a>';
$penultWordForLink = '<a href="' . $link . '">' . array_pop($arrWords) . ' ';
$resultArr[$i] = ' ' . implode(' ', $arrWords) . $penultWordForLink . $lastWordForLink;
break;
} else {
// Если в массиве 1 элемент , значит, по "обе стороны" от данного элемента теги, поэтому их надо обернуть в тег гиперссылки
// Получаем последнее слово с многоточием в конце
$lastWordForLink = array_pop($arrWords) . '...';
// Переписываем текущий элемент с добавлением пробела (в конце программы удалим)
$resultArr[$i] = ' ' . implode(' ', $arrWords) . $lastWordForLink;
// Создаём счётчики для подсчёта элементов "слева", содержащих теги, чтобы затем уместно поставить закрывающий тег гиперссылки справа
$countOpenTags = 0;
$countCloseTags = 0;
// Циклом for начинаем перебор элементов в обратном порядке с текущей позиции, чтобы определить предпоследнее слово ссылки
for ($j = $i - 1; $j > 0; $j--) {
// Каждый элемент массива проверяем на соответствие регулярному выражению
if (preg_match("|<[/][^>]+>|U", $resultArr[$j])) {
// Если TRUE, значит, тег - закрывающий
$countCloseTags++;
continue;
} elseif (preg_match("|<[^>]+>|U", $resultArr[$j])) {
// Если TRUE, значит, тег - открывающий, поэтому увеличиваем счётчик тегов и листаем дальше
$countOpenTags++;
continue;
// for ($k = $j; $k > 0; $k--) {}
} else {
// Если FALSE, значит, это текст
// Разбиваем по пробелу, чтобы получить массив слов
$arrWords = explode(' ', trim($resultArr[$j]));
if ($countCloseTags == 0) {
// Находим предпоследнее слово, добавляем открывающий тег гиперссылки и пробелы с двух сторон
$penultWordForLink = '<a href="' . $link . '">' . array_pop($arrWords) . ' ';
// Переписываем текущий элемент с добавлением пробела (в конце программы удалим) и прерываем цикл
$resultArr[$j] = ' ' . implode(' ', $arrWords) . $penultWordForLink;
break;
} else {
if (count($arrWords) > 1) {
$resultArr[$j + $countCloseTags] = '<a href="' . $link . '">' . $resultArr[$j + $countCloseTags];
break;
} else {
// Находим предпоследнее слово, добавляем открывающий тег гиперссылки и пробелы с двух сторон
$penultWordForLink = array_pop($arrWords) . ' ';
// Переписываем текущий элемент с добавлением пробела (в конце программы удалим) и прерываем цикл
$resultArr[$j - $countCloseTags] = '<a href="' . $link . '">' . $resultArr[$j - $countCloseTags];
break;
}
}
}
}
// Находим элемент справа, за которым должен быть закрывающий тег гиперссылки, переписываем его и обрываем цикл
$resultArr[$i + $countOpenTags] = $resultArr[$i + $countOpenTags] . '</a>';
break;
}
}
}
// Склеиваем результирующий массив
// Чистим входной текст от лишних пробелов
$shortText = preg_replace('/\s\s+/', ' ', implode($resultArr));
*/
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task 6</title>
</head>
<body>
<?php echo $shortText; ?>
</body>
</html>