Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум Регулярные Выражения

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Укоротить строку не нарушая расположение тегов
 
 автор: Eugene77   (08.02.2008 в 18:59)   письмо автору
 
 

Строка вот так может выглядеть:
<p>здесь текст..........Иной раз слишком длинный</p>
Может вот так:
<p>............................<img...../></p>
Или так:
<table><tr><td>....<table>...</table>..<table>..</table></td></tr></table>
Словом, вложенность может быть произвольная
Надо так сократить текст, чтобы это не привело к ошибочной разметке.
Изначально можно считать что все теги парные и вложены без ошибок (это отдельно проверяется)
Сокращать желательно с хвоста.

   
 
 автор: exp   (08.02.2008 в 20:13)   письмо автору
 
   для: Eugene77   (08.02.2008 в 18:59)
 

если просто брать текст между >< примерно так
<?php
$str 
= <<<TEXT
<p>здесь текст .Иной раз слишком длинный</p>
Может вот так:
<p>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAA<img...../></p>
Или так:
<table><tr><td>BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB<table>...</table>..<table>.
.</table>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCC</td></tr></table>
TEXT;

print 
preg_replace('#>([^<]{18,})<#se''">" . str_replace("\\\'", "\'", substr("$1", 0, 15)). "...<"'$str);
?>
но затрёт всё в тегах типа <script></script>

   
 
 автор: Eugene77   (09.02.2008 в 19:23)   письмо автору
 
   для: exp   (08.02.2008 в 20:13)
 

Гм.
Интересно...
Но, если я такое на форуме применю (каждый абзац сокращу на чуть-чуть) думаете красиво получится?
Кажется лучше было бы сократить насколько нужно последний абзац. Если этого не хватит -
выбросить его совсем, и перейти к попытке сократить следующий с конца.

   
 
 автор: Unkind   (09.02.2008 в 20:38)   письмо автору
 
   для: Eugene77   (09.02.2008 в 19:23)
 

Можно попробовать так:

<?php
header
('Content-type: text/plain; charset=utf-8');

function 
ht_substr($ht$limit, &$pair)
{
    if( 
$limit >= strlen($ht) )
    {
        return 
$ht;
    }

    
$ht preg_split('{(</?(\w+).*?>)}'$ht, -1PREG_SPLIT_NO_EMPTY PREG_SPLIT_DELIM_CAPTURE);

    for(
$i 0$k 1$level 0$cnt count($ht); $i $cnt$i++, $k++)
    {
        if( 
$ht[$i][0] == '<' )
        {
            
$tag strtolower($ht[$i 1]);

            if( 
in_array($tag$pair) )
            {
                
$level += ( $ht[$i][1] == '/' ) ? -: +1;
            }

            
$limit -= strlen($ht[$i]);

            unset( 
$ht[$i++ + 1] );
        }
        else
        {
            
$limit -= strlen($ht[$i]);
        }

        if( 
$level <= && $limit <= )
        {
            return 
implode(array_slice($ht0$k));
        }
    }
}

$pair_tags = array('p''a');

echo
ht_substr('<p>The quick brown fox jumped over the lazy dog</p><img src="" alt="" />'10$pair_tags),
"\r\n",
ht_substr('<p><a href="">The quick brown fox jumped over the lazy dog</a></p> ...'10$pair_tags),
"\r\n",
ht_substr('<img src="" alt="" />'10$pair_tags);
?>


Однако по умолчанию теги одиночные.

   
 
 автор: exp   (09.02.2008 в 22:16)   письмо автору
 
   для: Unkind   (09.02.2008 в 20:38)
 

тут так как спрашивается получится сделать только каким-нибудь способом который несколько раз раскладывает и складывает текст
, или просто нетрогая теги урезать только текст.
а так мне слабо-представляется задача , где пришлось-бы так дотошно разобраться в том как построена вложенность тегов. даже с одними только <table> и <p>, максимально что может сделать одно рег-выражение, то эт только найти самые вложенные блоки
<pre>
<?php 
$str 
= <<<T
<p>здесь текст<p>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAA<img...../></p></p> 
 
<table><tr><td>BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB<table>CCCCCCCCCCCCCCCCCCCCCCCCCCC</table><table>. 
.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD D</table>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE</td></tr>.
<table>FFFFFFFFFFFFFFFFFFFFF</table></table> 
T;

preg_match_all('#<(p|table)>(?>(?:(?!</?\\1>).)*|(?R))+</\\1>#si'$str$str);
var_dump($str[0]);
?>
</pre>
здесь не найдёт блоки BBBBBBBBB...... и EEEEEEEEEEEE..... и "здесь текст"

   
 
 автор: Eugene77   (10.02.2008 в 14:57)   письмо автору
 
   для: Unkind   (09.02.2008 в 20:38)
 

Есть поучительные дл яменя моменты в вашем коде, но без корректной обработки вложенных тегов мне не обойтись.
Вот такая мысль пришла мне в голову на основе всех этих обсуждений:
<?php
function get_max_len(){
    global 
$max_len;
    return 
$max_len;
}
function 
shorten($s){
    
$p '#(.*)<([a-z][a-z1-6]*)\b[^>]*>([^<>]*)</\\2\b[^>]*>(.*)#is'// Самый глубоко вложенный tag
    
for($i=0$i<18$i++){
        if(
strlen($s)<get_max_len()) return $s;
        
$s preg_replace_callback($pcreate_function('$args''
            $max_len=get_max_len();
            if(($d=strlen($args[0]) - strlen($args[3])) >= $max_len) return $args[1].$args[4]; // отбрасываем весь tag
            // Сокращаем содержимое тега:
            for($a=$args[3], $r=$max_len-$d; strlen($a)>=$r; $a=mb_substr($a,0, mb_strlen($a,"utf-8")-1,"utf-8"));
            return $args[1]."<".$args[2].">".$a."</".$args[2].">".$args[4];
        '
), $s);
    }
   echo 
' Cannot shorten'.$s;
}
$str "
<p>First text</p>
<b>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAA</b>
<table><tr><td>BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB</td></tr><tr><td>CCCCCCC<img ></td></tr></table>
<p>DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDDDDDD</p>
<cite>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE EEEEEEEEEEEEE</cite>
<h2>FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFF</h2>
"
;
$max_len=150;
echo 
htmlspecialchars(shorten($str));
?>


Посмотрите, пожалуйста, на предмет разумности такого кода и на предмет возникновения возможных ошибочных ситуаций.Уж больно странно как-то всё это выглядит, хотя вроде сработало несколько раз удачно.
Ещё надо будет подумать об откидывании одиночных тегов, но это я скорее всего сам справлюсь.

   
 
 автор: Unkind   (10.02.2008 в 22:19)   письмо автору
 
   для: Eugene77   (10.02.2008 в 14:57)
 

Непонятен смысл введения функции get_max_len().
На мой взгляд, с помощью create_function() лучше создавать только очень простые функции.

Код привязан с обязательному наличию тегов. Определите $str как

<?php
$str 
str_repeat('.'151);
?>


> $a=mb_substr($a,0, mb_strlen($a,"utf-8")-1,"utf-8"));

Это можно было бы сократить до

<?php
$a 
mb_substr($a0, -1'utf-8');
?>


> for($i=0; $i<18; $i++)
Почему именно 18?

И вообще зачем Вы ищите самую вложенную пару тегов? Зачем сокращать текст где-то в середине?

   
 
 автор: Eugene77   (11.02.2008 в 20:15)   письмо автору
 
   для: Unkind   (10.02.2008 в 22:19)
 

>Непонятен смысл введения функции get_max_len().
Я не сумел придумать ничего лучше этого довольно неприглядного способа, чтобы передать
значение максимальной длины в вызываемую preg_replace_callback ом функцию.
Подскакжите, пожалуйста, как это делается. это тем более желательно ибо максимальная длинна далеко не постоянна и функция будет вызываться с различными значениями этого параметра.

За подсказки -Спасибо!

>И вообще зачем Вы ищите самую вложенную пару тегов? Зачем сокращать текст где-то в середине?

Это не от большого ума. Просто я не сумел придумать ничего другого, чтобы сокращать текст, не касаясь вложенности тегов.

Пока вот такой вариант получается.Что-то ещё можно предпринять? Или указать слабые стороны?


<?
function get_max_len(){
    global 
$max_len;
    return 
$max_len;
}
function 
shorten($s){
    if(
$s==strip_tags($s)) $s='<p>'.$s.'</p>'// Это на случай если разметки не окажется
    
$p '#(.*)<([a-z][a-z1-6]*)\b[^>]*>([^<>]*)</\\2\b[^>]*>(.*)#is'// Самый глубоко вложенный tag
    
for($i=0$i<50$i++){
        if(
strlen($s)<get_max_len()) return $s;
        
$s1 preg_replace_callback($pcreate_function('$args''
            $max_len=get_max_len();
            if(($d=strlen($args[0]) - strlen($args[3])) >= $max_len) return $args[1].$args[4]; // отбрасываем весь tag
            // Сокращаем содержимое тега:
            for($a=$args[3], $r=$max_len-$d; strlen($a)>=$r; $a = mb_substr($a, 0, -1, "utf-8"));
            return $args[1]."<".$args[2].">".$a."</".$args[2].">".$args[4];
        '
), $s);
        if(
$i==30 or $s==$s1$s=strip_tags($s,'<p>');
        
$s=$s1;
    }
   
// на крайний случай, если ничего не помогло
   
$s=strip_tags($s);
   
$s=iconv('utf-8','utf-16',$s);
   
$s=substr($s,0,intval(get_max_len()/2)*2-8);
   
$s='<p>'.iconv('utf-16','utf-8',$s).'</p>';
}

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования