Guest User

Untitled

a guest
Aug 10th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.27 KB | None | 0 0
  1. Wordwrap / Cut Text in HTML string
  2. public function textWrap($string, $width)
  3. {
  4. $dom = new DOMDocument();
  5. $dom->loadHTML($string);
  6. foreach ($dom->getElementsByTagName('*') as $elem)
  7. {
  8. foreach ($elem->childNodes as $node)
  9. {
  10. if ($node->nodeType === XML_TEXT_NODE)
  11. {
  12. $text = trim($node->nodeValue);
  13. $length = mb_strlen($text);
  14. $width -= $length;
  15. if($width <= 0)
  16. {
  17. // Here, I would like to delete all next nodes
  18. // and cut the current nodeValue and finally return the string
  19. }
  20. }
  21. }
  22. }
  23. }
  24.  
  25. <p>
  26. <span class="Underline"><span class="Bold">Test to be cut</span></span>
  27. </p><p>Some text</p>
  28.  
  29. <p>
  30. <span class="Underline"><span class="Bold">Test to</span></span>
  31. </p>
  32.  
  33. $htmlFragment = <<<HTML
  34. <p>
  35. <span class="Underline"><span class="Bold">Test to be cut</span></span>
  36. </p><p>Some text </p>
  37. HTML;
  38.  
  39. $dom = new DOMDocument();
  40. $dom->loadHTML($htmlFragment);
  41. $parent = $dom->getElementsByTagName('body')->item(0);
  42. if (!$parent)
  43. {
  44. throw new Exception('Parent element not found.');
  45. }
  46.  
  47. $range = new TextRange($parent);
  48.  
  49. // find position where to cut the HTML textual represenation
  50. // by looking for a word or the at least matching whitespace
  51. // with a regular expression.
  52. $width = 17;
  53. $pattern = sprintf('~^.{0,%d}(?<=S)(?=s)|^.{0,%1$d}(?=s)~su', $width);
  54. $r = preg_match($pattern, $range, $matches);
  55. if (FALSE === $r)
  56. {
  57.     throw new Exception('Wordcut regex failed.');
  58. }
  59. if (!$r)
  60. {
  61. throw new Exception(sprintf('Text "%s" is not cut-able (should not happen).', $range));
  62. }
  63.  
  64. // chop-off the textnodes to make a cut in DOM possible
  65. $range->split($matches[0]);
  66. $nodes = $range->getNodes();
  67. $cutPosition = end($nodes);
  68.  
  69. // obtain list of elements to remove with xpath
  70. if (FALSE === $cutPosition)
  71. {
  72. // if there is no node, delete all parent children
  73. $cutPosition = $parent;
  74. $xpath = 'child::node()';
  75. }
  76. else
  77. {
  78. $xpath = 'following::node()';
  79. }
  80.  
  81. // execute xpath
  82. $xp = new DOMXPath($dom);
  83. $remove = $xp->query($xpath, $cutPosition);
  84. if (!$remove)
  85. {
  86. throw new Exception('XPath query failed to obtain elements to remove');
  87. }
  88.  
  89. // remove nodes
  90. foreach($remove as $node)
  91. {
  92. $node->parentNode->removeChild($node);
  93. }
  94.  
  95. // inner HTML (PHP >= 5.3.6)
  96. foreach($parent->childNodes as $node)
  97. {
  98. echo $dom->saveHTML($node);
  99. }
  100.  
  101. <p>
  102. <span class="Underline"><span class="Bold">Test to</span></span></p>
  103.  
  104. ...
  105. $range = new TextRange($parent);
  106. $trimmer = new TextRangeTrimmer($range);
  107. $trimmer->trim();
  108. ...
  109.  
  110. class TextRangeTrimmer
  111. {
  112. /**
  113. * @var TextRange
  114. */
  115. private $range;
  116.  
  117. /**
  118. * @var array
  119. */
  120. private $charlist;
  121.  
  122. public function __construct(TextRange $range, Array $charlist = NULL)
  123. {
  124. $this->range = $range;
  125. $this->setCharlist($charlist);
  126. }
  127. /**
  128. * @param array $charlist list of UTF-8 encoded characters
  129. * @throws InvalidArgumentException
  130. */
  131. public function setCharlist(Array $charlist = NULL)
  132. {
  133. if (NULL === $charlist)
  134. $charlist = str_split(" tnrx0B")
  135. ;
  136.  
  137. $list = array();
  138.  
  139. foreach($charlist as $char)
  140. {
  141. if (!is_string($char))
  142. {
  143. throw new InvalidArgumentException('Not an Array of strings.');
  144. }
  145. if (strlen($char))
  146. {
  147. $list[] = $char;
  148. }
  149. }
  150.  
  151. $this->charlist = array_flip($list);
  152. }
  153. /**
  154. * @return array characters
  155. */
  156. public function getCharlist()
  157. {
  158. return array_keys($this->charlist);
  159. }
  160. public function trim()
  161. {
  162. if (!$this->charlist) return;
  163. $this->ltrim();
  164. $this->rtrim();
  165. }
  166. /**
  167. * number of consecutive charcters of $charlist from $start to $direction
  168. *
  169. * @param array $charlist
  170. * @param int $start offset
  171. * @param int $direction 1: forward, -1: backward
  172. * @throws InvalidArgumentException
  173. */
  174. private function lengthOfCharacterSequence(Array $charlist, $start, $direction = 1)
  175. {
  176. $start = (int) $start;
  177. $direction = max(-1, min(1, $direction));
  178. if (!$direction) throw new InvalidArgumentException('Direction must be 1 or -1.');
  179.  
  180. $count = 0;
  181. for(;$char = $this->range->getCharacter($start), $char !== ''; $start += $direction, $count++)
  182. if (!isset($charlist[$char])) break;
  183.  
  184. return $count;
  185. }
  186. public function ltrim()
  187. {
  188. $count = $this->lengthOfCharacterSequence($this->charlist, 0);
  189.  
  190. if ($count)
  191. {
  192. $remainder = $this->range->split($count);
  193. foreach($this->range->getNodes() as $textNode)
  194. {
  195. $textNode->parentNode->removeChild($textNode);
  196. }
  197. $this->range->setNodes($remainder->getNodes());
  198. }
  199.  
  200. }
  201. public function rtrim()
  202. {
  203. $count = $this->lengthOfCharacterSequence($this->charlist, -1, -1);
  204.  
  205. if ($count)
  206. {
  207. $chop = $this->range->split(-$count);
  208. foreach($chop->getNodes() as $textNode)
  209. {
  210. $textNode->parentNode->removeChild($textNode);
  211. }
  212. }
  213. }
  214. }
Add Comment
Please, Sign In to add comment