PHP: ещё одна небольшая авторасстановка тегов
В очередной раз было лень расставлять теги "руками", то есть, нажимая кнопочки, вспомнил о простом решении отсюда, его оказалось легко адаптировать и к тому, что понадобилось сейчас.
На входе - текстовый файл в кодировке Юникода UTF-8, более-менее вычитанный, конечно. Формат для разметки должен быть максимально простым, я свой описал прямо в файле "теста", который приведу "как есть" с разрывами строк:
Если первым непустым символом строки "+" и за ним хотя бы один пробел - строка будет заголовком и выделится капсом. + Заголовок, е, ё! Строка текста, если последним словом в ней URL, станет ссылкой на этот URL. http://blog.kislenko.net/ Bторой абзац, просто следом за первым... Пустая строка до и после - блок станет цитатой, а если приведён одинокий URL в строке, то он станет ссылкой в своём отдельном абзаце, как вот этот: https://www.php.net/manual/ru/function.array-push.php Неважно, происходит это в цитате или нет, одинокий URL останется URL, а абзац - абзацам, здесь делаем это в цитате Символы "больше", "меньше" и некоторые другие неудобные, автозаменятся, абзацы необязательно вытягивать в одну строку, началом нового абзаца будет Большая буква в начале строки... Любой не-буквенный символ, например, > в первой непустой позиции тоже откроет новый абзац, потому что так всегда обозначают цитирование, а также абзац может открыться двойной кавычкой, дефисом и т.д. Пустые строки в начале и конце файла не мешают Тег <p> не закрываем сознательно, может быть, где-то придётся менять на <br> Hello, world - абзацы работают и для английского. https://ya.ru/ Если URL находится не последним и не единственным https://google.ru/ в строке и отделён хотя бы одним разделителем, он попытается "вписаться" в абзац, сделав якорем предыдущее или следующее слово. открыли новую цитатку для автозакрытия, будет ли она абзацем, зависит от первого непустого символа.
Вот что получилось в браузере:
вид полученной разметки в браузере
Чтобы не использовать страшную разметку по умолчанию, проверял вот с этим небольшим стилем (файл style.css
):
* { font-family: sans-serif; } h5 { margin: 5px 0; font-size: 120%; line-height: 120%; } p { margin: 5px 0; line-height: 140%; } blockquote { margin: 5px 0; color: #333333; background-color: #F0F0F0; border: 1px solid #D1D7DC; padding: 2px; line-height: 120%; } a[target="_blank"] { background-color: #FFFFCC; } #helpbox { width: 450px; font-size: 10px; }
Вот исходник (файл index.php
), проверялся в актуальной сборке XAMPP с PHP 8, преобразуемый текст тоже должен быть в кодировке UTF-8.
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="utf-8"> <title>Tagger</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <?php define ('MAX_LENGTH','96000'); $data = ''; if (isset($_POST['data'])) { $data = htmlspecialchars ($_POST['data'],ENT_NOQUOTES,'UTF-8'); } $file = $data; $result = ''; $error = ''; $file = preg_replace("/^(\s*\r?\n){3,}/mu","\r\n\r\n",trim($file)); //Убрать лишние пустые строки (кроме двух) $file = explode ("\n", $file); //Преобразовать в массив строк $quoted = true; if (count($file) > 1 or !empty($file[0])) foreach ($file as $str) { //Для каждой строки $str = trim($str); //Убрать лишние разделители в начале и конце $str = str_replace ( //Выполнить глобальные замены, символы <> уже заменены ["''", "«", "»", "…" , "—", "<...>", "<…>" ], ["\"", "\"", "\"", "...", "-", "[...]", "[...]" ], $str); $words = preg_split ('/[\s]+/', trim($str), -1, PREG_SPLIT_NO_EMPTY); //Получить массив лексем $len = count($words); if ($len == 0) { if (empty($str)) { //Пустая строка - открываем или закрываем цитату $result .= ($quoted ? '<blockquote>' : '</blockquote>')."\n"; $quoted = !$quoted; } } else if ($words[0] == '+') { //Символ "+" в первой позиции - заголовок array_shift ($words); if (!count($words)) array_push ($words, 'Заголовок'); $result .= '<h5>'.implode(' ',$words).'</h5>'."\n"; } else if ($len == 1) { if (myurlencode($words[0])) { //Отдельный URL в строке $result .= '<p><a href="'.my_url_encode($words[0]).'" target="_blank">'.$words[0].'</a></p>'."\n"; } else { //Просто отдельное слово $result .= start_delim($str).$words[0]."\n"; } } else if ($len > 1) { if (myurlencode($words[$len-1]) and urls_cnt ($words) == 1) { //Последнее слово в строке = URL и он один $url = $words[$len-1]; $words = pack_punct (array_slice($words,0,$len-1)); $wd = implode(' ',$words); $result .= '<p>'.'<a href="'.my_url_encode($url).'" target="_blank">'.$wd.'</a></p>'."\n"; } else { for ($i = 0; $i < $len; $i++) { //Смотрим все слова if (myurlencode($words[$i])) { //Если URL if ($i == 0) { //Первым в строке if (myurlencode($words[1])) { $error .= '<p><b>Ошибка в строке "'.$str.'", 2 URL подряд</b></p>'; break; } $words[1] = '<a href="'.my_url_encode($words[0]).'" target="_blank">'.$words[1].'</a>'; array_shift ($words); $len = count ($words); } else { //Не первым в строке if (myurlencode($words[$i-1])) { $error .= '<p><b>Ошибка в строке "'.$str.'", 2 URL подряд</b></p>'; break; } $wd = punct($words[$i-1]); $words[$i-1] = $wd[0].'<a href="'.my_url_encode($words[$i]).'" target="_blank">'.$wd[1].'</a>'.$wd[2]; array_splice ($words, $i, 1); $len = count ($words); } } } $words = pack_punct ($words); $len = count ($words); for ($i = 0; $i < $len; $i++) { $wd = punct($words[$i]); if (empty($wd[1])) { $result = ($wd[0] == '-' ? $result : rtrim($result)).($i==0?'<p>':'').$wd[0]; } else { if ($i==0) $result .= start_delim($wd[1]); $result .= $wd[0].$wd[1].$wd[2]; } $result .= ($i < $len - 1 ? ' ' : ''); } $result .= "\n"; } } } if (!$quoted) $result .= '</blockquote>'; function punct ($string) { //вернёт [знаки препинания до, строка, знаки препинания после] $pattern = '/^([\p{P}]+)?(.*?)([\p{P}]+)?$/u'; $result = ["","",""]; if (preg_match($pattern, $string, $matches)) { for ($i = 1; $i < 4; $i++) if (!empty($matches[$i])) $result[$i-1] = $matches[$i]; } if ($result[0]=='&' and mb_substr($result[1],0,3,'UTF-8')=='lt;') { $result[0]= ''; $result[1]= '&'.$result[1]; } if ($result[2]==';' and mb_substr($result[1],-3,NULL,'UTF-8')=='>') { $result[2]= ''; $result[1]= $result[1].';'; } return $result; } function pack_punct ($words) { //"Упаковать" отдельные знаки препинания $n = count ($words); if ($n < 1) return []; if ($n == 1) return [$words[0]]; $new_words = []; for ($i = 0; $i < $n; $i++) { $wd = punct($words[$i]); if (empty($wd[1])) { if ($wd[0]=='-') array_push ($new_words,$wd[0]); else if ($i==0) { array_push ($new_words,$wd[0].($i < $n - 1 ? $words[$i+1] : '')); $i++; } else { $new_words[count($new_words)-1] .= $wd[0]; } } else array_push ($new_words,$wd[0].$wd[1].$wd[2]); } return $new_words; } function start_delim ($w) { //Надо ли начинать новый абзац $c = mb_substr (strip_tags($w),0,1,'UTF-8'); $cs = mb_strtoupper($c,'UTF-8'); if ($cs==$c or $cs=='-') return '<p>'; return ' '; } function urls_cnt ($words) { //Количество URL в строке $n = count ($words); $cnt = 0; for ($i = 0; $i < $n; $i++) if (myurlencode($words[$i])) $cnt++; return $cnt; } function my_url_encode($s) { $s= strtr ($s, array ( " "=> "%20", "а"=>"%D0%B0", "А"=>"%D0%90","б"=>"%D0%B1", "Б"=>"%D0%91", "в"=>"%D0%B2", "В"=>"%D0%92", "г"=>"%D0%B3", "Г"=>"%D0%93", "д"=>"%D0%B4", "Д"=>"%D0%94", "е"=>"%D0%B5", "Е"=>"%D0%95", "ё"=>"%D1%91", "Ё"=>"%D0%81", "ж"=>"%D0%B6", "Ж"=>"%D0%96", "з"=>"%D0%B7", "З"=>"%D0%97", "и"=>"%D0%B8", "И"=>"%D0%98", "й"=>"%D0%B9", "Й"=>"%D0%99", "к"=>"%D0%BA", "К"=>"%D0%9A", "л"=>"%D0%BB", "Л"=>"%D0%9B", "м"=>"%D0%BC", "М"=>"%D0%9C", "н"=>"%D0%BD", "Н"=>"%D0%9D", "о"=>"%D0%BE", "О"=>"%D0%9E", "п"=>"%D0%BF", "П"=>"%D0%9F", "р"=>"%D1%80", "Р"=>"%D0%A0", "с"=>"%D1%81", "С"=>"%D0%A1", "т"=>"%D1%82", "Т"=>"%D0%A2", "у"=>"%D1%83", "У"=>"%D0%A3", "ф"=>"%D1%84", "Ф"=>"%D0%A4", "х"=>"%D1%85", "Х"=>"%D0%A5", "ц"=>"%D1%86", "Ц"=>"%D0%A6", "ч"=>"%D1%87", "Ч"=>"%D0%A7", "ш"=>"%D1%88", "Ш"=>"%D0%A8", "щ"=>"%D1%89", "Щ"=>"%D0%A9", "ъ"=>"%D1%8A", "Ъ"=>"%D0%AA", "ы"=>"%D1%8B", "Ы"=>"%D0%AB", "ь"=>"%D1%8C", "Ь"=>"%D0%AC", "э"=>"%D1%8D", "Э"=>"%D0%AD", "ю"=>"%D1%8E", "Ю"=>"%D0%AE", "я"=>"%D1%8F", "Я"=>"%D0%AF")); return $s; } function myurlencode ($url) { //true или false if (filter_var($url, FILTER_VALIDATE_URL)) return true; if (filter_var(my_url_encode($url), FILTER_VALIDATE_URL)) return true; return false; } ?> <script src="./scripts.js" charset="utf-8"></script> <noscript> <p>Для работы всех функций приложения включите Javascript в браузере.</p> </noscript> <h5>Авторасстановка тегов</h5> <p> <script>showIcons();</script> <a href="http://blog.kislenko.net/show.php?id=2699" target="_blank">Страница скрипта</a> </p> <form action="index.php" method="post" name="myform"> <textarea rows="24" cols="82" name="data" id="data" required placeholder="Данные" maxlength="<?php echo MAX_LENGTH;?>" onselect="storeCaret(this);checkTextlen(<?php echo MAX_LENGTH;?>);" onclick="storeCaret(this);checkTextlen(<?php echo MAX_LENGTH;?>);" onkeyup="storeCaret(this);checkTextlen(<?php echo MAX_LENGTH;?>);"><?php echo "$data"; ?></textarea> <textarea rows="24" cols="82" name="result" id="result" placeholder="Результат"><?php echo "$result"; ?></textarea> <p> <input type="submit" name="action" value="Выполнить"> <input type="button" value="Очистить" onclick="clearMe();"> <small><span id="helpbox"></span></small> </p> </form> <?php if (!empty($error)) { echo '<p>'.$error.'</p>'; } if (!empty($result)) { echo htmlspecialchars_decode ($result,ENT_NOQUOTES); } ?> </body> </html>
Файл scripts.js
и картинки можно получить по прямым ссылкам: скрипт, картинки.
P.S. Если нужно две цитаты подряд, оставляем между ними две пустых строки:
Текст Цитата 1, Возможно, многострочная Цитата2 Снова текст
На основе скрипта и для описанного формата организован небольшой сервис для авторасстановки тегов, дальнейшие исправления и дополнения будут вноситься только в него (что не исключает обновления листинга выше).
Открыть сервис для авторасстановки тегов в новом окне/вкладке
версия до 19.05.24
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Tagger</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<?php
define ('MAX_LENGTH','96000');
$data = '';
if (isset($_POST['data'])) {
$data = htmlspecialchars ($_POST['data'],ENT_NOQUOTES,'UTF-8');
}
$file = $data;
$result = '';
$error = '';
$file = preg_replace("/^(\s*\r?\n){3,}/mu","\r\n\r\n",trim($file)); //Убрать лишние пустые строки (кроме двух)
$file = explode ("\n", $file); //Преобразовать в массив строк
$quoted = true;
if (count($file) > 1 or !empty($file[0])) foreach ($file as $str) { //Для каждой строки
$str = trim($str); //Убрать лишние разделители в начале и конце
$str = str_replace ( //Выполнить глобальные замены, символы <> уже заменены
["''", "«", "»", "…" , "—" ],
["\"", "\"", "\"", "...", "-" ],
$str);
$words = preg_split ('/[\s]+/', $str); //Получить массив лексем
$len = count($words);
if ($words[0] == '+') { //Символ "+" в первой позиции - заголовок, делаем его КАПСом
array_shift ($words);
if (!count($words)) array_push ($words, 'Заголовок');
$result .= '<h5>'.mb_strtoupper (implode(' ',$words),'UTF-8').'</h5>'."\n";
}
else if ($len == 1) {
if (empty($str)) { //Пустая строка - открываем или закрываем цитату
$result .= ($quoted ? '<blockquote>' : '</blockquote>')."\n";
$quoted = !$quoted;
}
else if (myurlencode($words[0])) { //Отдельный URL в строке
$result .= '<p><a href="'.my_url_encode($words[0]).'" target="_blank">'.$words[0].'</a></p>'."\n";
}
else { //Просто отдельное слово
$result .= start_delim($str).$words[0]."\n";
}
}
else if ($len > 1) {
if (myurlencode($words[$len-1]) and urls_cnt ($words) == 1) {
//Последнее слово в строке = URL и он один
$words = pack_commas ($words);
$result .= '<p><a href="'.my_url_encode($words[$len-1]).'" target="_blank">'.implode(' ',array_slice($words,0,$len-1)).
'</a></p>'."\n";
}
else {
for ($i = 0; $i < $len; $i++) { //Смотрим все слова
if (myurlencode($words[$i])) { //Если URL
if ($i == 0) { //Первым в строке
if (myurlencode($words[1])) {
$error .= '<p>Ошибка в строке "'.$str.'", 2 URL подряд</p>';
break;
}
$words[1] = '<a href="'.my_url_encode($words[0]).'" target="_blank">'.$words[1].'</a>';
array_shift ($words);
$len = count ($words);
}
else { //Не первым в строке
if (myurlencode($words[$i-1])) {
$error .= '<p>Ошибка в строке "'.$str.'", 2 URL подряд</p>';
break;
}
$words[$i-1] = '<a href="'.my_url_encode($words[$i]).'" target="_blank">'.$words[$i-1].'</a>';
array_splice ($words, $i, 1);
$len = count ($words);
}
}
}
$words = pack_commas ($words);
$result .= start_delim($words[0]).implode(' ',$words)."\n"; //Выводим слова
}
}
}
if (!$quoted) $result .= '</blockquote>';
function pack_commas ($words) { //"Упаковать" отдельные знаки препинания
$n = count ($words);
if ($n < 1) return [];
if ($n == 1) return [$words[0]];
$new_words = [$words[0]]; $j = 1;
$s = ['.',',','!','?','!?','?!','...',"\"",';',':',"\'",')'];
for ($i = 1; $i < $n; $i++) {
if (in_array($words[$i],$s)) {
$new_words[$j-1] .= $words[$i];
continue;
}
$new_words[$j++] = $words[$i];
}
return $new_words;
}
function start_delim ($w) { //Надо ли начинать новый абзац
$c = mb_substr (strip_tags($w),0,1,'UTF-8');
if (mb_strtoupper($c,'UTF-8')==$c) return '<p>';
return ' ';
}
function urls_cnt ($words) { //Количество URL в строке
$n = count ($words);
$cnt = 0;
for ($i = 0; $i < $n; $i++)
if (myurlencode($words[$i])) $cnt++;
return $cnt;
}
function my_url_encode($s) {
$s= strtr ($s, array (
" "=> "%20", "а"=>"%D0%B0", "А"=>"%D0%90","б"=>"%D0%B1", "Б"=>"%D0%91", "в"=>"%D0%B2", "В"=>"%D0%92",
"г"=>"%D0%B3", "Г"=>"%D0%93", "д"=>"%D0%B4", "Д"=>"%D0%94", "е"=>"%D0%B5", "Е"=>"%D0%95",
"ё"=>"%D1%91", "Ё"=>"%D0%81", "ж"=>"%D0%B6", "Ж"=>"%D0%96", "з"=>"%D0%B7", "З"=>"%D0%97",
"и"=>"%D0%B8", "И"=>"%D0%98", "й"=>"%D0%B9", "Й"=>"%D0%99", "к"=>"%D0%BA", "К"=>"%D0%9A",
"л"=>"%D0%BB", "Л"=>"%D0%9B", "м"=>"%D0%BC", "М"=>"%D0%9C", "н"=>"%D0%BD", "Н"=>"%D0%9D",
"о"=>"%D0%BE", "О"=>"%D0%9E", "п"=>"%D0%BF", "П"=>"%D0%9F", "р"=>"%D1%80", "Р"=>"%D0%A0",
"с"=>"%D1%81", "С"=>"%D0%A1", "т"=>"%D1%82", "Т"=>"%D0%A2", "у"=>"%D1%83", "У"=>"%D0%A3",
"ф"=>"%D1%84", "Ф"=>"%D0%A4", "х"=>"%D1%85", "Х"=>"%D0%A5", "ц"=>"%D1%86", "Ц"=>"%D0%A6",
"ч"=>"%D1%87", "Ч"=>"%D0%A7", "ш"=>"%D1%88", "Ш"=>"%D0%A8", "щ"=>"%D1%89", "Щ"=>"%D0%A9",
"ъ"=>"%D1%8A", "Ъ"=>"%D0%AA", "ы"=>"%D1%8B", "Ы"=>"%D0%AB", "ь"=>"%D1%8C", "Ь"=>"%D0%AC",
"э"=>"%D1%8D", "Э"=>"%D0%AD", "ю"=>"%D1%8E", "Ю"=>"%D0%AE", "я"=>"%D1%8F", "Я"=>"%D0%AF"));
return $s;
}
function myurlencode ($url) { //true или false
if (filter_var($url, FILTER_VALIDATE_URL)) return true;
if (filter_var(my_url_encode($url), FILTER_VALIDATE_URL)) return true;
return false;
}
?>
<script src="./scripts.js" charset="utf-8"></script>
<noscript>
<p>Для работы всех функций приложения включите Javascript в браузере.</p>
</noscript>
<h5>Авторасстановка тегов</h5>
<p>
<script>showIcons();</script>
<a href="http://blog.kislenko.net/show.php?id=2699" target="_blank">Страница скрипта</a>
</p>
<form action="index.php" method="post" name="myform">
<textarea rows="24" cols="82" name="data" id="data" required placeholder="Данные"
maxlength="<?php echo MAX_LENGTH;?>"
onselect="storeCaret(this);checkTextlen(<?php echo MAX_LENGTH;?>);"
onclick="storeCaret(this);checkTextlen(<?php echo MAX_LENGTH;?>);"
onkeyup="storeCaret(this);checkTextlen(<?php echo MAX_LENGTH;?>);"><?php echo "$data"; ?></textarea>
<textarea rows="24" cols="82" name="result" id="result" placeholder="Результат"><?php echo "$result"; ?></textarea>
<p>
<input type="submit" name="action" value="Выполнить">
<input type="button" value="Очистить" onclick="clearMe();">
<small><span id="helpbox"></span></small>
</p>
</form>
<?php
if (!empty($error)) {
echo '<p>'.$error.'</p>';
}
if (!empty($result)) {
echo htmlspecialchars_decode ($result,ENT_NOQUOTES);
}
?>
</body>
</html>
01.05.2021, 13:44 [1195 просмотров]