我想截断一些文本(从数据库或文本文件加载),但其中包含HTML,因此包含了标签,并且将返回较少的文本。然后,这可能导致标签未关闭或部分关闭(因此Tidy可能无法正常工作,并且内容仍然较少)。我如何基于文本截断(并且可能在到达表时停止,因为这可能会导致更复杂的问题)。
substr("Hello, my <strong>name</strong> is <em>Sam</em>. I´m a web developer.",0,26)."..."
将导致:
Hello, my <strong>name</st...
我想要的是:
Hello, my <strong>name</strong> is <em>Sam</em>. I´m...
我怎样才能做到这一点?
虽然我的问题是关于如何在PHP中进行操作,但最好知道如何在C#中进行操作…要么应该可以,因为我认为我可以将方法移植过来(除非它是内置的)方法)。
还要注意,我包括了一个HTML实体´-必须将其视为单个字符(而不是本示例中的7个字符)。
´
strip_tags 是一个备用,但我会丢失格式和链接,并且HTML实体仍然会出现问题。
strip_tags
假设您使用的是有效的XHTML,则解析HTML并确保正确处理标签非常简单。您只需要跟踪到目前为止已经打开了哪些标签,并确保“在您出门时”再次将其关闭。
<?php header('Content-type: text/plain; charset=utf-8'); function printTruncated($maxLength, $html, $isUtf8=true) { $printedLength = 0; $position = 0; $tags = array(); // For UTF-8, we need to count multibyte sequences as one character. $re = $isUtf8 ? '{</?([a-z]+)[^>]*>|&#?[a-zA-Z0-9]+;|[\x80-\xFF][\x80-\xBF]*}' : '{</?([a-z]+)[^>]*>|&#?[a-zA-Z0-9]+;}'; while ($printedLength < $maxLength && preg_match($re, $html, $match, PREG_OFFSET_CAPTURE, $position)) { list($tag, $tagPosition) = $match[0]; // Print text leading up to the tag. $str = substr($html, $position, $tagPosition - $position); if ($printedLength + strlen($str) > $maxLength) { print(substr($str, 0, $maxLength - $printedLength)); $printedLength = $maxLength; break; } print($str); $printedLength += strlen($str); if ($printedLength >= $maxLength) break; if ($tag[0] == '&' || ord($tag) >= 0x80) { // Pass the entity or UTF-8 multibyte sequence through unchanged. print($tag); $printedLength++; } else { // Handle the tag. $tagName = $match[1][0]; if ($tag[1] == '/') { // This is a closing tag. $openingTag = array_pop($tags); assert($openingTag == $tagName); // check that tags are properly nested. print($tag); } else if ($tag[strlen($tag) - 2] == '/') { // Self-closing tag. print($tag); } else { // Opening tag. print($tag); $tags[] = $tagName; } } // Continue after the tag. $position = $tagPosition + strlen($tag); } // Print any remaining text. if ($printedLength < $maxLength && $position < strlen($html)) print(substr($html, $position, $maxLength - $printedLength)); // Close any open tags. while (!empty($tags)) printf('</%s>', array_pop($tags)); } printTruncated(10, '<b><Hello></b> <img src="world.png" alt="" /> world!'); print("\n"); printTruncated(10, '<table><tr><td>Heck, </td><td>throw</td></tr><tr><td>in a</td><td>table</td></tr></table>'); print("\n"); printTruncated(10, "<em><b>Hello</b>w\xC3\xB8rld!</em>"); print("\n");
编码说明 :上面的代码假定XHTML是UTF-8编码的。还支持ASCII兼容的单字节编码(例如Latin-1),只需将其false作为第三个参数传递即可。不支持其他多字节编码,尽管您可能会mb_convert_encoding在调用该函数之前先转换为UTF-8,然后在每个print语句中再次转换回来,以获取支持。
false
mb_convert_encoding
print
(不过,您应该 始终 使用UTF-8。)
编辑 :更新为处理字符实体和UTF-8。修复了以下错误:如果该字符是一个字符实体,该函数将打印一个字符过多。