БлогNot. PHP: ещё одна небольшая авторасстановка тегов

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 ( //Выполнить глобальные замены, символы <> уже заменены 
   ["''", "«",  "»",  "…"  , "—", "&lt;...&gt;", "&lt;…&gt;" ],
   ["\"", "\"", "\"", "...", "-", "[...]",        "[...]" ], 
   $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')=='&gt') {
   $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>
 &nbsp;&nbsp;&nbsp;<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 просмотров]


теги: css html ссылки textprocessing php форматы

К этой статье пока нет комментариев, Ваш будет первым