Truncate a HTML formatted text with SMARTY

五迷三道 提交于 2020-01-13 15:00:11

问题


I've got a variable which is formatted with random HTML code. I call it to {$text} and i truncate it.

The value is for example:

<div>Lorem <i>ipsum <b>dolor <span>sit </span>amet</b>, con</i> elit.</div>

If i truncate the text's first ~30 letters, I'll get this:

<div>Lorem <i>ipsum <b>dolor <span>sit 

The problem is, I can't close the elements. So, I need a script, which check the <*> elements in the code (where * could be anything), and if it dont have a close tag, close 'em.

Please help me in this. Thanks.

Solution after hours, and 4 vote-up @ stackoverflow:

PHP:

...
function closetags($content) {
   preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $content, $result);
    $openedtags = $result[1];
  preg_match_all('#</([a-z]+)>#iU', $content, $result);
 $closedtags = $result[1];
  $len_opened = count($openedtags);
  if (count($closedtags) == $len_opened) {
       return $content;
  }
  $openedtags = array_reverse($openedtags);
  for ($i=0; $i < $len_opened; $i++) {
        if (!in_array($openedtags[$i], $closedtags)) {
         $content .= '</'.$openedtags[$i].'>';
       } else {
           unset($closedtags[array_search($openedtags[$i], $closedtags)]);
        }
  }
  return $content;
}
...

the TPL:

{$pages[j].text|truncate:300|@closetags}

回答1:


Pull out all the open tags, push them into an array (array_1) one-by-one.

Pull out all of the closed tags, push them into an array (array_2) one-by-on (this includes self closing tags).

For the tags in the first array (array_1) that are not found in the second array (array_2), add them to the html.

[edit]

Of course, this method fails miserably if you do not write proper html... but whatchagonnado?

Another way would be to look ahead in the string to see which tags are closed and close them as needed.




回答2:


To simplify, if the code is valid XML before truncating and you don't cut off tags in half, the algorithm would be something like this:

  • Push opening tags onto a stack
  • Pop them off when you find the closing tag (which will match if the code is valid)
  • When you get to the end, start popping to create closing. The remaining tags should be appended to the original (truncated) text.

Example:

<div>Lorem <i>ipsum <b>dolor <span>sit </span>amet</b><div>
  • Push "div","i","b","span"
  • Found closing tag "span"
  • Pop "span"
  • Found closing tag "b"
  • Pop "b"
  • Push "div"
  • End of truncated text
  • Pop "div" --> add </div> to text
  • Pop "b" --> add </b> to text
  • Pop "i" --> add </i> to text
  • Pop "div" --> add </div> to text
  • End



回答3:


for other people like me and you I found this code ,I think is a better solution

add this file named "modifier.html_substr.php"

        <?php
    /*
    * Smarty plugin
    *
    -------------------------------------------------------------
    * File: modifier.html_substr.php
    * Type: modifier
    * Name: html_substr
    * Version: 1.0
    * Date: June 19th, 2003
    * Purpose: Cut a string preserving any tag nesting and matching.
    * Install: Drop into the plugin directory.
    * Author: Original Javascript Code: Benjamin Lupu <hide@address.com>
    * Translation to PHP & Smarty: Edward Dale <hide@address.com>
    * Modification to add a string: Sebastian Kuhlmann <hide@address.com>
    * Modification to put the added string before closing <p> or <li> tags by Peter Carter http://www.podhawk.com
    -------------------------------------------------------------
    */
    function smarty_modifier_html_substr($string, $length, $addstring="")
    {

    //some nice italics for the add-string
    if (!empty($addstring)) $addstring = "<i> " . $addstring . "</i>";

    if (strlen($string) > $length) {
    if( !empty( $string ) && $length>0 ) {
    $isText = true;
    $ret = "";
    $i = 0;

    $currentChar = "";
    $lastSpacePosition = -1;
    $lastChar = "";

    $tagsArray = array();
    $currentTag = "";
    $tagLevel = 0;

    $addstringAdded = false;

    $noTagLength = strlen( strip_tags( $string ) );

    // Parser loop
    for( $j=0; $j<strlen( $string ); $j++ ) {

    $currentChar = substr( $string, $j, 1 );
    $ret .= $currentChar;

    // Lesser than event
    if( $currentChar == "<") $isText = false;

      // Character handler
      if( $isText ) {

          // Memorize last space position
          if( $currentChar == " " ) { $lastSpacePosition = $j; }
          else { $lastChar = $currentChar; }

          $i++;
          } else {
          $currentTag .= $currentChar;
          }

          // Greater than event
          if( $currentChar == ">" ) {
              $isText = true;

              // Opening tag handler
              if( ( strpos( $currentTag, "<" ) !== FALSE ) &&
              ( strpos( $currentTag, "/>" ) === FALSE ) &&
              ( strpos( $currentTag, "</") === FALSE ) ) {

              // Tag has attribute(s)
              if( strpos( $currentTag, " " ) !== FALSE ) {
                  $currentTag = substr( $currentTag, 1, strpos( $currentTag, " " ) - 1 );
                  } else {
                  // Tag doesn't have attribute(s)
                  $currentTag = substr( $currentTag, 1, -1 );
                  }

                  array_push( $tagsArray, $currentTag );

                  } else if( strpos( $currentTag, "</" ) !== FALSE ) {
                  array_pop( $tagsArray );
                  }

              $currentTag = "";
              }

          if( $i >= $length) {
          break;
          }
      }

    // Cut HTML string at last space position
    if( $length < $noTagLength ) {
    if( $lastSpacePosition != -1 ) {
    $ret = substr( $string, 0, $lastSpacePosition );
    } else {
    $ret = substr( $string, $j );
    }
    }

    // Close broken XHTML elements
    while( sizeof( $tagsArray ) != 0 ) {
    $aTag = array_pop( $tagsArray );
      // if a <p> or <li> tag needs to be closed, put the add-string in first
      if (($aTag == "p" || $aTag == "li") && strlen($string) > $length) {
      $ret .= $addstring;
      $addstringAdded = true;
      }
    $ret .= "</" . $aTag . ">\n";
    }

    } else {
    $ret = "";
    }

    // if we have not added the add-string already 
    if ( strlen($string) > $length && $addstringAdded == false) {
    return( $ret.$addstring );
    }
    else {
    return ( $ret );
    }
    }
    else {
    return ( $string );
    }
    }
    ?>

usage

{$yourdata|html_substr:300:' ...'}


来源:https://stackoverflow.com/questions/2671053/truncate-a-html-formatted-text-with-smarty

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!