{!$htmlConent|truncate:30} Jak ořezat jen text (ignorovat HTML tagy)
- Endrju
- Člen | 147
Ahoj, problém je asi jasný z předmětu.
Proměnna $htmlConent
obsahuje naformátovaný text pomocí HTML
tagů (práce CKEditoru), který pak v šabloně zobrazuji takto:
{!$htmlConent}
Nyní bych chtěl tento text ořezat. Problém je ovšem v tom, že tato konstukce
{!$htmlConent|truncate:30}
k počtu znaků, které mají být ořezány započítává také HTML tagy. Tedy nejen, že může být způsobeno, že se nezobrazí vůbec nic z text, protože po ořezání zbydou jen HTML tagy, ale také nejsou tagy dokončeny, což může rozhodit layout webu.
Jak to udělat, aniž bych ztratil formátování textu (odstraněním HTML tagů) a mohl ořezat jen text? Přitom, by se všchny nedokončené HTML tagy uzavřely?
PS: nebyl jsem si jistý zda to mám hlásit jako chybu (když tak to tam přesuňte), protože možna takové použití nebylo ani zamýšleno. Nicméně něco takového by bylo docela užitečné. Řešili jste to už někdo? Jde to nějak udělat s pomocí Nette?
EDIT: Když jsem před přidáním tohoto tématu hledal na foru, zda tu už
někdo něco podobného neřešil, tak jsem narazil na něco takového:
{!$htmlConent|html|truncate:30}
. To ale nefunguje (ani jsem
nezjišťoval co ten parametr html dělá..) a vyhazuje to chybu:
MemberAccessException - Call to undefined method Template::html()
.
Osobně mě napadlo, jak by se to dalo zhruba implementovat, ale nechci předbíhat pokud něco takového už je. Musel bych projít celý htmlContent s tím, že bych si do pomocné proměnné ukládal text, který jsem už prošel a inkrementoval bych čítač znaků jen když bych narazil na text, který není v HTML tagu (text který se na stránce zobrazuje). Až bych narazil na limit, tak bych buď musel nějak dokončit HTML tagy a nebo dojet až do konce s tím, že bych ignoroval text a bral jen HTML tagy.
Editoval Endrju (10. 3. 2010 21:24)
- Endrju
- Člen | 147
Aha, odpověděl jsi dřív než jsem stihl editovat post.. No, to nerad slyším :-/. Neznáte nějaký efektivní způsob na identifikaci HTML tagů (pro případ, že to budu muset impelmentovat)?
Nebo nemáte nekdo ještě lepší řešení, než to které jsem popsal ve svém předchozím příspěvku?
- Mikulas Dite
- Člen | 756
No, html neni regulární, takže to přes regexp pude asi složitě. Ale zkusim z hlavy:
Do toho helperu dej něco na styl
<?php
function helperClip($subject, $limit)
{
$elements = preg_match_all('~<.*?>~s', $subject, $matches);
$raw_text = preg_replace('~<.*?>~s', '&__splitter;', $subject);
$raw_text_array = explode('&__splitter;', $raw_text);
$shortened_by = 0;
while($shortened_by < $limit)
{
if (strlen($raw_text_array[-1]) > $limit) {
$raw_text_array[-1] = substr($raw_text_array[-1], 0, $limit);
break;
} else {
$shortened_by += strlen($raw_text_array[-1]);
unset($raw_text_array[-1]);
}
}
return /*tady střídavě poskádat $raw_text_array a $elements (začínat podle počtu prvků)*/;
}
?>
Jo tak to sem se docela rozepsal, to sem ani nečekal. Netestoval sem to, takže tam určitě bude nějaké to typo. Plus závěr sem nedodělal, ale to by neměl být problém, viz. comment v kódu.
//Edit: jo, ty záporné indexy nejdou, je to
end($raw_text_array)
Editoval Mikulas Dite (10. 3. 2010 21:32)
- toka
- Člen | 253
Používám tento helper:
class MyString {
public static function truncate($string, $length, $e = '…', $isHTML = TRUE){
$i = 0;
$tags = array();
if($isHTML) {
preg_match_all('/<[^>]+>([^<]*)/', $string, $match, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
foreach($match as $object) {
if($object[0][1] - $i >= $length) break;
$tag = substr(strtok($object[0][0], " \t\n\r\0\x0B>"), 1);
if($tag[0] != '/') $tags[] = $tag;
elseif(end($tags) == substr($tag, 1)) array_pop($tags);
$i += $object[1][1] - $object[0][1];
}
}
return substr($string, 0, $length = min(strlen($string), $length + $i)) . (count($tags = array_reverse($tags)) ? '</' . implode('></', $tags) . '>' : '') . (strlen($string) > $length ? $e : '');
}
}
- Endrju
- Člen | 147
to Mikulas Dite: diky :). V hlave me napadalo trochu jine reseni, protze jsem pred par mesici delal Crawler v .NET a tam jsem podobne veci resil. To co poslal toka funguje, takze uz to dale nezkoumam.
to toka: Parada, odzkousel jsem to a funguje (je tam jen jedna drobnost..). Byl bys prosim te jeste laskavy a zkusil trosku okomentovat jednotlive casti kodu, abych vedel co to presne dela? Mohl bych si to samozrejmne pozjistovat nastudovanim tech funkci ktere jsi pouzil, ale takto to bude snazsi.
Pouziti:
<div id="content"><?php echo MyString::truncate($htmlConent, 27); ?></div>
K te male drobnosti.. Vstupni text:
<p style="text-align: justify;">Vážení fotbaloví fanoušci,</p>
<p style="text-align: justify;">vítejte ....</p>
Vystup (text je dlouhý 23 znaků, ale zadával jsem 27):
Vážení fotbaloví fanou�
…
Výstup v HTML:
<p>Vážení fotbaloví fanou�</p>
…
Nevím jak to je s kódováním a jak se převedou znaky s diakritikou,
protže to vypdadá, že ta funkce počíta znak s diakritikou jako více
znaků a nebo tam je někde renonc… :).
Když bych to chtěl zkrátit na 28 znaků, tak se znak ‚š‘
vypíše „celý“
No a pak bych ještě chtěl, aby se ty tři tečky zobrazily hned za zkráceným slovem (ještě v tom odstavci). Vypadá to takhle nejasně..
Myslíš, že by jsi to dokázal takto upravit?
Jiank moc děkuji za ušetřenou práci a čas. Fakt moc dík!
- Endrju
- Člen | 147
Pokud je to otázka na mě Ondro, tak bych řekl, že ne. Zatím jsem si
vystačil s Nette funkcemi, takže pokud není něco přímo tam, tak ne.
Nevím jak jinak mám přijít na to, zda nějakou takovou funkci používám.
Text vkladám pomocí CKEditoru, ten je pak v databázi uložen jako
utf8_bin
a zde se přes phpMyAdmina také v pořádku zobrazuje
(žádné podivné znaky).
Zkusil jsem s malou improvizací* předhodit stejný text helperu
truncate
. Ten funguje tak, že zkracuje celá slova, dokud mu
nezbyde jediné slovo, to pak zkracuje po znacích a pak přidá trojtečku.
Jinak zanechává celá slova.
Ta improvizace tedy spočívala v tom, že jsem musel slovo se znakem ‚š‘ dát jako první slovo textu (jinak by mi to zkrátilo celé slovo) a pak postupně jsem zkracoval, až jsem narazil na místo, kde by měl být odebrán znak ‚š‘. Po jeho odebrání (zkrácení) tam nezbyde zádný balast.. Čili helper truncate to dělá vpořádku.
Podle mě je to způsobeno tou funkcí, kterou dodal „toca“. Když tu funkci nepoužiju, tak se znaky zobrazí správně. Když ji použiju, tak ne.
Bohužel jsem jetě neanalyzoval, jak přesně ta funkce od toca funguje, tak nevím co s tím textem ta funkce provede.. Any idea?
EDIT: přidávám funkci truncate z Nette.. třeba by šla nějak upravit..
/**
* Truncates string to maximal length.
* @param string UTF-8 encoding
* @param int
* @param string UTF-8 encoding
* @return string
*/
public static function truncate($s, $maxLen, $append = "\xE2\x80\xA6")
{
if (iconv_strlen($s, 'UTF-8') > $maxLen) {
$maxLen = $maxLen - iconv_strlen($append, 'UTF-8');
if ($maxLen < 1) {
return $append;
} elseif (preg_match('#^.{1,'.$maxLen.'}(?=[\s\x00-@\[-`{-~])#us', $s, $matches)) {
return $matches[0] . $append;
} else {
return iconv_substr($s, 0, $maxLen, 'UTF-8') . $append;
}
}
return $s;
}
Editoval Endrju (11. 3. 2010 1:14)
- Ondřej Mirtes
- Člen | 1536
Aha, nevšim jsem si, že toka tady uveřejnil svůj helper. Změnil bych v něm tuto řádku:
$tag = substr(strtok($object[0][0], " \t\n\r\0\x0B>"), 1);
na tuto:
$tag = mb_substr(strtok($object[0][0], " \t\n\r\0\x0B>"), 1, 1024, 'UTF-8');
Ta hodnota 1024 je maximální možná délka vraceného stringu, kdyžtak si to prodluž. Musel jsem jsem jí tam napsat, protože kýžené kódování je až čtvrtý parametr :o)
Třeba to pomůže.
- Endrju
- Člen | 147
Diky Ondro, zkusil jsem a ee, pořád stejný problémek..
Jinak ten škaredý znak se zobrazí, i když použiju
iconv_substr
s kódováním místo mb_substr
.
Nebylo by lepší nějak předělat původní Nette String::truncate? Chtěl bych totiž, aby mi to zachovávalo celá slova (pokud je k dispozici více než jedno slovo) jako to dělá Nettovský truncate. Pokuším se tomu trchu porozumět, ale zadím jsem v podstatě na bodu mrazu. Nevím jak na to.
Editoval Endrju (11. 3. 2010 1:52)
- Endrju
- Člen | 147
Hm, trochu jsem zkoušel analyzovat ten kód od toca.. jetě ne úplně, ale napadla mě pak jedna věc a zatím jsem nenašel žádnou chybu.
na posledním řádku jsem také zaměnil substr za mb_substr tedy na posledním řádku zaměnit tohle:
return substr($string, 0, $length = min(strlen($string), $length + $i))
za tohle:
return mb_substr($string, 0, $length = min(strlen($string), $length + $i), 'UTF-8')
- ten zbytek na tom řádku tam samozřejmě nechat.
Editoval Endrju (11. 3. 2010 23:49)
- Endrju
- Člen | 147
Ondřej Mirtes napsal(a):
Ta hodnota 1024 je maximální možná délka vraceného stringu, kdyžtak si to prodluž. Musel jsem jsem jí tam napsat, protože kýžené kódování je až čtvrtý parametr :o)
Teď mě napadlo – zkoušel jsem hledat max. délku stringu v proměnné.. – Ondro jsi si jistý, že maximální délka stringu je 1024? http://cz.php.net/…s.string.php
It is no problem for a string to become very large. PHP imposes no boundary on the size of a string; the only limit is the available memory of the computer on which PHP is running.
No a když už je tam třeba dávat nějakou délku, tak možná než tam cpát nějaké vymyšlené číslo a případně si zkrátit vstup by bylo lepší tam dát aspoň délku toho vstupního stringu.
Editoval Endrju (11. 3. 2010 2:21)
- Ondřej Mirtes
- Člen | 1536
Endrju: Však jsem řekl, můžeš si tam dát jaké číslo chceš, klidně i vypočtené :)
- Endrju
- Člen | 147
okej :).
Jinak to prevedeni na UTF-8 staci pouze na konci u toho return.
public static function truncate($string, $length, $e = "\xE2\x80\xA6", $isHTML = TRUE){
$i = 0;
$tags = array();
if($isHTML) {
preg_match_all('/<[^>]+>([^<]*)/', $string, $match, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
foreach($match as $object) {
if($object[0][1] - $i >= $length) break;
$token = strtok($object[0][0], " \t\n\r\0\x0B>");
$tag = substr($token, 1);
if($tag[0] != '/') $tags[] = $tag;
elseif(end($tags) == substr($tag, 1)) array_pop($tags);
$i += $object[1][1] - $object[0][1];
}
}
return iconv_substr($string, 0, $length = min(strlen($string), $length + $i), 'UTF-8') . (count($tags = array_reverse($tags)) ? '</' . implode('></', $tags) . '>' : '') . (strlen($string) > $length ? $e : '');
}
Asi (dle meho usudku) nebude úplně v pořádku ten regulární výraz. Můžete to někdo zkontrolovat? Nejlépe i odzkoušet?
Nevím proč se mi ve výstupu zobrazuje ten znak ‚<‘? Je to 27. znak ve výstupnímm textu, ale ve vstupním nic takového není! Za čárkou ve vstupním textu následuje rovnou ukonční odstavce..
Pro odzkoušení použijte toto:
<?php echo MyString::truncate($htmlConent, 27); ?>
A jako vstup $htmlConent:
<p style="text-align: justify;">Vážení fotbaloví fanoušci,</p>
<p style="text-align: justify;">vítejte ....</p>
Měli by jste dostat výstup (v prohlížeči):
Vážení fotbaloví fanoušci,<
…
Výstup v HTML:
<p style="text-align: justify;">Vážení fotbaloví fanoušci,<</p>
…
Když zadám zkrácení na 26 znaků, tak se zobrazí
Vážení fotbaloví fanoušci,
a ten znak ‚<‘ už tam
není, což je prozměnu v pořádku.
Pak se mi nelíbí, že se trojtečka zobrazuje někdy mimo odstavec. Třeba když zadám 26 znaků a méně, tak se trojtečka zobrazí až za ukončeným odstavcem (předpokládám, že to je problém někde v tom uzavírání nedokončených tagů). Když zadám ale 28 znaků, tak se trojtečka zobrazí hned za textem ještě než se ukončí odstavec:
Vážení fotbaloví fanoušci,…
Html:
<p style="text-align: justify;">Vážení fotbaloví fanoušci,…</p>
Zkuste na to prosím někdo mrknout, trápím se tu s tím už pěkně dlouho a nevím co s tím.
Editoval Endrju (11. 3. 2010 3:57)
- srigi
- Nette Blogger | 558
Chalani chalani asi malo citate Jakuba Vranu, on uz to riesil a riesil aj problem kodovania.
- Mikulas Dite
- Člen | 756
Nedalo mi to a napsal jsem vylepšenou verzi toho svého helperu.
Nyní perfektrně zvládá rozeznávat html tagy, neselže ani na
<p id=">">
, používá mb knihovny,
započítává délku suffixu do limitu a hlavně, maže prázdné hmtl
tagy a vkládá suffix před poslední element.
<?php
public function truncate($string, $limit)
{
$suffix = ' …';
$tag_pattern = '</?\w+(?:(?:\s+\w+(?:\s*=\s*(?:".*?"|\'.*?\'|[^\'">\s]+))?)+\s*|\s*)/?>';
preg_match_all('~' . $tag_pattern . '~s', $string, $elements);
$text_array = preg_split('~' . $tag_pattern . '~s', $string);
$truncated_by = 0;
while (mb_strlen(implode('', $text_array)) > $limit - mb_strlen($suffix)){
$len = mb_strlen(end($text_array));
$truncated_by += $len;
if ($len < $limit - $truncated_by) {
unset( $text_array[count($text_array)-1] );
unset( $elements[0][count($text_array)-1] );
} else {
$text_array[count($text_array)-1] = mb_substr(end($text_array), 0, $limit - $truncated_by);
}
}
$output = '';
for ($i = 0; $i <= max(array_keys($elements)) || $i <= max(array_keys($text_array)); $i++) {
if (isset ($text_array[$i]))
$output .= $text_array[$i];
if ($i + 1 == max(array_keys($text_array)))
$output .= $suffix;
if (isset($elements[0][$i]))
$output .= $elements[0][$i];
}
return trim($output);
}
?>
Tedy z
<p id=">" style="text-align: justify;">Vážení fotbaloví fanoušci,</p>
<p style="text-align: justify;">vítejte ....</p>
udělá při truncate:30
<p id=">" style="text-align: justify;">Vážení fotbaloví fanoušci, …</p>
Editoval Mikulas Dite (11. 3. 2010 20:17)
- Endrju
- Člen | 147
Mikulas Dite napsal(a):
Nedalo mi to a napsal jsem vylepšenou verzi toho svého helperu.
…
Pekna prace :). Ma to ale asi jeste neco nedoreseneho.. Jednak magicke cislo 27 :)… Zkrat text na 27 znaku a 3 tecky se zobrazi pred zkracovanym textem – pred odstavcem.
…
<p style="text-align: justify;">Vážení fotbaloví fanoušci,</p>
Pro delku 20 prozmenu dostanu:
Fatal Error: Maximum execution time of 30 seconds exceeded
. Ale
jinak pekna prace, ja si zatim netroufnul to zkusit napsat, takze smekam..
- Endrju
- Člen | 147
srigi, diky za ten link.
Zkousel jsem pouzit nejake funkce, ktere tam Jakub Vrana. Konkretne jsem se
rozhodl pouzivat a nasledne upravit (vysledek nebyl 100%) tu
„function xhtml_cut($s, $limit) { ... }
“ a
„function html_cut($s, $limit) { ... }
“. Nezobrazoval se ale
presny pocet znaku, jaky jsem zadal (samozrejme jsem odkomentoval tu cast kodu,
ktera zpracovava UTF-8). Tudiz jsem debugoval a zjistil, ze i kdyz budu
pouzivat multibyte string funkce, tak pri prochazeni po znacich budou znaky
s diakritikou tak jako tak pocitany jako vice znaku. Zkusil jsem tedy vsupni
retezec preformatovat z UTF-8
na Windows-1250
pomoci
funkce iconv (jen si ted nejsem jisty, zda je mozne, aby se nejaky
UTF-8 znak neprevedl korektne na Windows-1250 a naopak – nemate
nejakou zkusenost?). Po preformatovani, se pak znaky s diakritikou
pocitaji jako jeden celistvy znak (a i pri debugovani – prochazeni znak po
znaku – se zobrazuji spravne).
Pridana funkcionalita:
- Na zacatku funkce je vstupni retezec preveden z
UTF-8
naWindows-1250
- Pridan append (defaultne trojtecka) za zkraceny text (nepovinny parametr
funkce)
- je pridan jeste pred vsemi ukoncovacimi tagy a ostatnimi tagy, ktere jsou za zobrazenym textem. Tedy by se nemelo stat, ze by se append zobrzil za ukoncenym odstavcem, odradkovanim nebo treba vodorovnou carou misto za textem v odstavci.
- Vysledna delka textu je zkracena o delku retezce append, aby sedela maximalni pozdadovana delka zobrazeneho textu
- Pokud je adpped ponechan defaultne na trojtecku, tak jsou z konce retezce odmazany vsechny ostatni tecky, aby nevzniklo treba neco jako „A tak tomu tedy bylo .....“ + trojtecka.
- Nakonec je text preveden zase zpet z Windows-1250 do UTF-8.
Tridu jsem umistil do slozky app/helpers/MyStringHelper.php
:
/**
* MyString Helper
*
* @author Endrju
* @package Application
*/
abstract class MyString {
/**
* Truncates string containing XHTML tags to maximal length
* @param string UTF-8 encoding
* @param int
* @param string UTF-8 encoding
* @return string
* @copyright Jakub Vrána, http://php.vrana.cz/
* @author Endrju (modifications)
*/
public static function xhtmlTruncate($s, $maxLen, $append = "\xE2\x80\xA6")
{
// ma vubec smysl retezec zkracovat?
if (iconv_strlen($s, 'UTF-8') > $maxLen) {
// prekodujeme z UTF-8 do windows-1250,
// znaky s diakritikou atp pak budou pocitany jako jeden cely znak
$s = iconv('UTF-8', 'windows-1250//TRANSLIT', $s);
$append = iconv('UTF-8', 'windows-1250//TRANSLIT', $append);
$length = 0;
$tags = array(); // dosud neuzavřené značky
for ($i=0; $i < strlen($s) && $length < $maxLen; $i++) {
switch ($s[$i]) {
case '<':
// načtení značky
$start = $i+1;
while ($i < strlen($s) && $s[$i] != '>' && !ctype_space($s[$i])) {
$i++;
}
$tag = substr($s, $start, $i - $start);
// přeskočení případných atributů
$in_quote = '';
while ($i < strlen($s) && ($in_quote || $s[$i] != '>')) {
if (($s[$i] == '"' || $s[$i] == "'") && !$in_quote) {
$in_quote = $s[$i];
} elseif ($in_quote == $s[$i]) {
$in_quote = '';
}
$i++;
}
if ($s[$start] == '/') { // uzavírací značka
array_shift($tags); // v XHTML dokumentu musí být vždy uzavřena poslední neuzavřená značka
} elseif ($s[$i-1] != '/') { // otevírací značka
array_unshift($tags, $tag);
}
break;
case '&':
$length++;
while ($i < strlen($s) && $s[$i] != ';') {
$i++;
}
break;
default:
$length++;
// V případě kódování UTF-8:
while ($i+1 < strlen($s) && ord($s[$i+1]) > 127 && ord($s[$i+1]) < 192) {
$i++;
}
}
}
// zkratime reztezec o delku $append, pokud neni $apped delsi nez samotny retezec
$s = ($length > strlen($append)) ? substr($s, 0, $i - strlen($append)) : substr($s, 0, $i);
// uzavreme vsechny tagy
$enclosingTags = "";
if ($tags) {
$enclosingTags .= "</" . implode("></", $tags) . ">";
}
// Nyni potrebujeme probublat od konce pres vsechny tagy na konci textu $s,
$s_beforeInnerEnclosingTags = $s;
$innerEnclosingTags = "";
while (substr(rtrim($s_beforeInnerEnclosingTags), - 1, 1) == ">") {
$innerEnclosingTags = strrchr($s_beforeInnerEnclosingTags, "<");
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, strlen($s_beforeInnerEnclosingTags) - strlen($innerEnclosingTags));
}
// Pokud je nastaven $append na trojtecku,
// orezeme jeste samotne tecky na konci rezce (pokud nejake jsou)
if ($append == iconv('UTF-8', 'windows-1250//TRANSLIT', "\xE2\x80\xA6")) {
$s_beforeInnerEnclosingTags = rtrim($s_beforeInnerEnclosingTags, '.');
}
// Nyni vse spojime dohromady a pridame $append
$s = $s_beforeInnerEnclosingTags . $append . $innerEnclosingTags . $enclosingTags;
// Vystupni retezec prekodovany zpet z windows-1250 do UTF-8
$s = iconv('windows-1250', 'UTF-8//TRANSLIT', $s);
}
return $s;
}
/**
* Truncates string containing HTML tags to maximal length
* @param string UTF-8 encoding
* @param int
* @param string UTF-8 encoding
* @return string
* @copyright Jakub Vrána, http://php.vrana.cz/
* @author Endrju (modifications)
*/
public static function htmlTruncate($s, $maxLen, $append = "\xE2\x80\xA6")
{
// ma vubec smysl retezec zkracovat?
if (iconv_strlen($s, 'UTF-8') > $maxLen) {
static $empty_tags = array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param');
// prekodujeme z UTF-8 do windows-1250,
// znaky s diakritikou atp pak budou pocitany jako jeden cely znak
$s = iconv('UTF-8', 'windows-1250//TRANSLIT', $s);
$append = iconv('UTF-8', 'windows-1250//TRANSLIT', $append);
$length = 0;
$tags = array(); // dosud neuzavřené značky
for ($i=0; $i < strlen($s) && $length < $maxLen; $i++) {
switch ($s{$i}) {
case '<':
// načtení značky
$start = $i+1;
while ($i < strlen($s) && $s{$i} != '>' && !ctype_space($s{$i})) {
$i++;
}
$tag = strtolower(substr($s, $start, $i - $start));
// přeskočení případných atributů
$in_quote = '';
while ($i < strlen($s) && ($in_quote || $s{$i} != '>')) {
if (($s{$i} == '"' || $s{$i} == "'") && !$in_quote) {
$in_quote = $s{$i};
} elseif ($in_quote == $s{$i}) {
$in_quote = '';
}
$i++;
}
if ($s{$start} == '/') { // uzavírací značka
$tags = array_slice($tags, array_search(substr($tag, 1), $tags) + 1);
} elseif ($s{$i-1} != '/' && !in_array($tag, $empty_tags)) { // otevírací značka
array_unshift($tags, $tag);
}
break;
case '&':
$length++;
while ($i < strlen($s) && $s{$i} != ';') {
$i++;
}
break;
default:
$length++;
// V případě kódování UTF-8:
while ($i+1 < strlen($s) && ord($s[$i+1]) > 127 && ord($s[$i+1]) < 192) {
$i++;
}
}
}
// zkratime reztezec o delku $append, pokud neni $apped delsi nez samotny retezec
$s = ($length > strlen($append)) ? substr($s, 0, $i - strlen($append)) : substr($s, 0, $i);
// uzavreme vsechny tagy
$enclosingTags = "";
if ($tags) {
$enclosingTags .= "</" . implode("></", $tags) . ">";
}
// Nyni potrebujeme probublat od konce pres vsechny tagy na konci textu $s,
$s_beforeInnerEnclosingTags = $s;
$innerEnclosingTags = "";
while (substr(rtrim($s_beforeInnerEnclosingTags), - 1, 1) == ">") {
$innerEnclosingTags = strrchr($s_beforeInnerEnclosingTags, "<");
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, strlen($s_beforeInnerEnclosingTags) - strlen($innerEnclosingTags));
}
// Pokud je nastaven $append na trojtecku,
// orezeme jeste samotne tecky na konci rezce (pokud nejake jsou)
if ($append == iconv('UTF-8', 'windows-1250//TRANSLIT', "\xE2\x80\xA6")) {
$s_beforeInnerEnclosingTags = rtrim($s_beforeInnerEnclosingTags, '.');
}
// Nyni vse spojime dohromady a pridame $append
$s = $s_beforeInnerEnclosingTags . $append . $innerEnclosingTags . $enclosingTags;
// Vystupni retezec prekodovany zpet z windows-1250 do UTF-8
$s = iconv('windows-1250', 'UTF-8//TRANSLIT', $s);
}
return $s;
}
}
Do app/presenters/BasePresenter.php
jsem zaregistroval
helpery:
abstract class BasePresenter extends Presenter
{
public $oldLayoutMode = FALSE;
public $oldModuleMode = FALSE;
protected function beforeRender()
{
$this->template->registerHelper('xhtmlTruncate', array('MyString', 'xhtmlTruncate'));
$this->template->registerHelper('htmlTruncate', array('MyString', 'htmlTruncate'));
}
}
Pouziti pak v jakekoli sablone napr:
{block content}
<div id="xhtmlContent">{!$newsItem->content|xhtmlTruncate:300}</div>
<div id="htmlContent">{!$newsItem->content|htmlTruncate:300}</div>
{/block}
Premyslel jsem taky jak docilit toho, aby se zkracovala cela slova – aby to nezkracovalo v pulce slova (pokud v retezci teda neni jen jedine slovo). Tedy presne tak, jak funguje Nette\String::truncate()
Bohuzel jsem narazil na problem, ze kdyz jsem zkracoval text o zbytky slov, tak se napriklad stalo, ze nebyly odstraneny tagy, ktere to slovo obaluji a pak mi to rozhodilo layout nebo narusilo jine tagy.. Kdyby jste si s tim nekdo zkusili pohrat a prijit na to, tak by to bylo strasne fajn :).
Jinak diky vsem za pomoc :)
Editoval Endrju (12. 3. 2010 18:28)
- MzK
- Člen | 127
uff, todle je už pro mě vyšší dívčí… Ale záleží na html vs
xhtml.. Dobře to popsal Jakub Vrána.
http://php.vrana.cz/…znackami.php
- Endrju
- Člen | 147
Editoval jsem svuj predchozi post + znacne upravil kod a pridal tam i upravenou funkci pro HtmlTruncate. Testoval jsem obe funkce na vstupech, ktere vygeneroval CKEditor a vysledek byl naprosto stejny.
zacatecnik: Funkce kterou zde v komentarich postnul „Mike“ nefunguje. On na zacatku funkce zkrati cely text na pozadovanou delku (nebere v potazt to, ze tam muzou byt HTML znacky a ze tim prichazi o zobrazovany text. Pak v tom co mu zbylo najde posledni mezeru v domeni ze je to posledni slovo zobrazeneho textu, tak to co predchazi te mezere pak pusti dal do funkce. No a v nejhorsim pripade pusti do funkce jen cast nejake HTML znacky s parametry a zadny text..
Editoval Endrju (12. 3. 2010 18:26)
- Endrju
- Člen | 147
No nedalo mi to a do ted jsem na tom sedel… :-). Jednak tam byly jeste nejake nedostatky a ja to chtel funkcni v podstate uplne stejne jako Nette\String::truncate(), coz se mi nakonec, huraaaa, povedlo :-).
Mozna se budu castecne opakovat, ale kdyz uz je to (doufam) funkcni, tak at
je to pohromade.. Funkce ma tri parametry, stejne jako jste zvykli u
String::truncate($s, $maxLen, $append = "\xE2\x80\xA6")
a funguje
to uplne stejne, s tim rozdilem, ze jako vstup nedavate plain text, ale (X)HTML
text. Odzkousene to mam na vstupech, ktere generuje CKEditor (ver. 3.1) a pak na pár
co jsem si jen tak zkoušel…
Na pocet radku je to mozna dlouhe, ale hodne delaji ty komentare (zvyk). Coz mi ale za rok treba pomuze rozpomenout jak jsem to delal nebo kdyz by to po me nekdo cetl :-).
Obe metody xhtmlTruncate
a htmlTruncate
funguji
stejne:
- Pridan
append
(defaultne trojtecka) za zkraceny text (nepovinny parametr funkce).- je pridan jeste pred vsechny ukoncovaci tagy a ostatnimi tagy, ktere jsou za
zobrazenym textem. Tedy by se nemelo stat, ze by se
append
zobrzil za ukoncenym odstavcem, odradkovanim nebo treba vodorovnou carou misto za textem v odstavci.
- je pridan jeste pred vsechny ukoncovaci tagy a ostatnimi tagy, ktere jsou za
zobrazenym textem. Tedy by se nemelo stat, ze by se
- Vysledna delka textu je zkracena o delku retezce
append
, aby sedela maximalni pozdadovana delka zobrazeneho textu. - Pokud je
append
ponechan defaultne na trojtecku, tak jsou z konce retezce odmazany vsechny ostatni tecky, aby nevzniklo treba neco jako „A tak tomu tedy bylo .....“ + trojtecka. - Zkracovana jsou cela slova, ale tak aby nebyla prekrocena maximalni
pozadovana delka textu.
- Jako separatory pro oddelovani slov jsem zvolil tyto (muzete si je
upravit):
$separators = array (' ', ',', '.', ';', '?', '!', ':');
- Dva a vice stejnych separatoru bezprostredne za sebou nejsou brany jako separatory (zduvodneno je to v kodu v komentarich)
- Pokud zustava jen posledni slovo k zobrazeni, je zkracovano po znacich.
- Jako separatory pro oddelovani slov jsem zvolil tyto (muzete si je
upravit):
To je asi vsechno, pokud jsem na neco nezapomel.
Tridu jsem umistil do slozky app/helpers/MyStringHelper.php
:
/**
* MyString Helper
*
* @author Endrju
* @package Application
*/
abstract class MyString {
/**
* Truncates string containing XHTML tags to maximal length
* @param string UTF-8 encoding
* @param int
* @param string UTF-8 encoding
* @return string
* @copyright Jakub Vrána, http://php.vrana.cz/
* @author Endrju (modifications)
*/
public static function xhtmlTruncate($s, $maxLen, $append = "\xE2\x80\xA6")
{
// ma vubec smysl retezec zkracovat?
if (iconv_strlen($s, 'UTF-8') > $maxLen) {
// zkratime $maxLen o delku $append
$maxLen = $maxLen - iconv_strlen($append, 'UTF-8');
// pokud je nyni $maxLen kratsi bez $appedm vratime samotonty $append
if ($maxLen < iconv_strlen($append, 'UTF-8')) {
return $append;
}
// vybrane znaky, ktere muzou ukoncovat vetu nebo vyznam casti vety
$separators = array (' ', ',', '.', ';', '?', '!', ':');
$pos = 0; // pozice posledniho nalezeneho separatoru
// prekodujeme z UTF-8 do windows-1250,
// znaky s diakritikou atp pak budou pocitany jako jeden cely znak
$s = iconv('UTF-8', 'windows-1250//TRANSLIT', $s);
$INITAL_S = $s; // originalni vstupni retezec $s, ktery nebude po dobu behu programu zmenen.
$append = iconv('UTF-8', 'windows-1250//TRANSLIT', $append);
// odstranime neviditelne znaky,
// ktere se ve vygenerovanem a zobrazenem HTML textu stejne nezobrazi
$customWhitespaces = array("\0x09", "\0x0A", "\0x0D", "\0x00", "\0x0B");
foreach ($customWhitespaces AS $customWhitespace) {
$s = trim($s, $customWhitespace);
}
$length = 0;
$tags = array(); // dosud neuzavřené značky
for ($i=0; $i < strlen($s) && $length < $maxLen; $i++) {
switch ($s[$i]) {
case '<':
// načtení značky
$start = $i+1;
while ($i < strlen($s) && $s[$i] != '>' && !ctype_space($s[$i])) {
$i++;
}
$tag = strtolower(substr($s, $start, $i - $start));
// přeskočení případných atributů
$in_quote = '';
while ($i < strlen($s) && ($in_quote || $s[$i] != '>')) {
if (($s[$i] == '"' || $s[$i] == "'") && !$in_quote) {
$in_quote = $s[$i];
} elseif ($in_quote == $s[$i]) {
$in_quote = '';
}
$i++;
}
if ($s[$start] == '/') { // uzavírací značka
array_shift($tags); // v XHTML dokumentu musí být vždy uzavřena poslední neuzavřená značka
} elseif ($s[$i-1] != '/') { // otevírací značka
array_unshift($tags, $tag);
}
break;
case '&':
$length++;
while ($i < strlen($s) && $s[$i] != ';') {
$i++;
}
break;
default:
$length++;
/* V případě kódování UTF-8:
while ($i+1 < strlen($s) && ord($s[$i+1]) > 127 && ord($s[$i+1]) < 192) {
$i++;
}*/
// je znak separatorem?
if (in_array($s[$i], $separators)) {
// * a neni nasledujici (nebo predchozi) znak totozny,
// jako nyni nacteny separator?
if (($s[$i] != $s[$i+1]) && ($s[$i-1] != $s[$i])) {
$pos = $i; // pak ulozime pozici separatoru
} // nakonec tak ziskame pozici posledniho separatoru
// * tou druhou podminkou chceme zachytit pripady, kdy je v textu
// nekolik separatotu (napr. tecek) za sebou, pak to nebudeme povazovat za separator,
// ale jako vyznam k predchazejicimu slovu (vete).
// Navic pokud by takovy separator byl na konci oriznuteho textu, bude tak v podstate
// nahrazen volitelnym retezcem $append (defaultne trojtecka).
}
}
}
// pokud nenalezneme hledany pocet znaku, obsah je nejspis slozen ciste z HTML tagu
// (napr. flashova videa a jine medialni objekty)
if ($length >= $maxLen) {
$s = substr($s, 0, $i);
// uzavreme vsechny tagy
$enclosingTags = "";
if ($tags) {
$enclosingTags .= "</" . implode("></", $tags) . ">";
}
// Nyni potrebujeme probublat od konce pres vsechny tagy az na konec zobrazovaneho textu $s
// (tam pak budeme pridavat $append)
$s_beforeInnerEnclosingTags = $s;
$innerEnclosingTags = "";
while (substr(rtrim($s_beforeInnerEnclosingTags), - 1, 1) == ">") {
$innerEnclosingTags = strrchr($s_beforeInnerEnclosingTags, "<");
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, strlen($s_beforeInnerEnclosingTags) - strlen($innerEnclosingTags));
}
// Pokud je nastaven $append na trojtecku,
// orezeme jeste samotne tecky na konci rezce (pokud nejake jsou)
if ($append == iconv('UTF-8', 'windows-1250//TRANSLIT', "\xE2\x80\xA6")) {
$s_beforeInnerEnclosingTags = rtrim($s_beforeInnerEnclosingTags, '.');
}
// pokud byl nejaky separator nalezen
// a zaroven znak za zkracovanym textem neni separatorem
if (($pos > 0) && (!in_array(substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1), $separators))) {
// tak orizneme text za poslednim nalezenym separatorem
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, $pos);
}
// nebo take pokud byl nejaky separator nalezen
// a zaroven 2 znaky za zkracovanym textem jsou 2 stejne separatory (viz. * o neco vyse - stejny pripad)
else if (($pos > 0) && (in_array(substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1), $separators)) && ((substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1) == ((substr($INITAL_S, strlen($s_beforeInnerEnclosingTags) + 1, 1)))))) {
// tak orizneme text za poslednim nalezenym separatorem a dva vyse zminene ignorujeme
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, $pos);
}
// Nyni vse spojime dohromady a pripojime $append
$s = $s_beforeInnerEnclosingTags . $append . $innerEnclosingTags . $enclosingTags;
}
// Vystupni retezec prekodujeme zpet z windows-1250 do UTF-8
$s = iconv('windows-1250', 'UTF-8//TRANSLIT', $s);
}
return $s;
}
/**
* Truncates string containing HTML tags to maximal length
* @param string UTF-8 encoding
* @param int
* @param string UTF-8 encoding
* @return string
* @copyright Jakub Vrána, http://php.vrana.cz/
* @author Endrju (modifications)
*/
public static function htmlTruncate($s, $maxLen, $append = "\xE2\x80\xA6")
{
// ma vubec smysl retezec zkracovat?
if (iconv_strlen($s, 'UTF-8') > $maxLen) {
// zkratime $maxLen o delku $append
$maxLen = $maxLen - iconv_strlen($append, 'UTF-8');
// pokud je nyni $maxLen kratsi bez $appedm vratime samotonty $append
if ($maxLen < iconv_strlen($append, 'UTF-8')) {
return $append;
}
static $empty_tags = array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param');
// vybrane znaky, ktere muzou ukoncovat vetu nebo vyznam casti vety
$separators = array (' ', ',', '.', ';', '?', '!', ':');
$pos = 0; // pozice posledniho nalezeneho separatoru
// prekodujeme z UTF-8 do windows-1250,
// znaky s diakritikou atp pak budou pocitany jako jeden cely znak
$s = iconv('UTF-8', 'windows-1250//TRANSLIT', $s);
$INITAL_S = $s; // originalni vstupni retezec $s, ktery nebude po dobu behu programu zmenen.
$append = iconv('UTF-8', 'windows-1250//TRANSLIT', $append);
// odstranime neviditelne znaky,
// ktere se ve vygenerovanem a zobrazenem HTML textu stejne nezobrazi
$customWhitespaces = array("\0x09", "\0x0A", "\0x0D", "\0x00", "\0x0B");
foreach ($customWhitespaces AS $customWhitespace) {
$s = trim($s, $customWhitespace);
}
$length = 0;
$tags = array(); // dosud neuzavřené značky
for ($i=0; $i < strlen($s) && $length < $maxLen; $i++) {
switch ($s[$i]) {
case '<':
// načtení značky
$start = $i+1;
while ($i < strlen($s) && $s[$i] != '>' && !ctype_space($s[$i])) {
$i++;
}
$tag = strtolower(substr($s, $start, $i - $start));
// přeskočení případných atributů
$in_quote = '';
while ($i < strlen($s) && ($in_quote || $s[$i] != '>')) {
if (($s[$i] == '"' || $s[$i] == "'") && !$in_quote) {
$in_quote = $s[$i];
} elseif ($in_quote == $s[$i]) {
$in_quote = '';
}
$i++;
}
if ($s{$start} == '/') { // uzavírací značka
$tags = array_slice($tags, array_search(substr($tag, 1), $tags) + 1);
} elseif ($s{$i-1} != '/' && !in_array($tag, $empty_tags)) { // otevírací značka
array_unshift($tags, $tag);
}
break;
case '&':
$length++;
while ($i < strlen($s) && $s[$i] != ';') {
$i++;
}
break;
default:
$length++;
/* V případě kódování UTF-8:
while ($i+1 < strlen($s) && ord($s[$i+1]) > 127 && ord($s[$i+1]) < 192) {
$i++;
}*/
// je znak separatorem?
if (in_array($s[$i], $separators)) {
// * a neni nasledujici (nebo predchozi) znak totozny,
// jako nyni nacteny separator?
if (($s[$i] != $s[$i+1]) && ($s[$i-1] != $s[$i])) {
$pos = $i; // pak ulozime pozici separatoru
} // nakonec tak ziskame pozici posledniho separatoru
// * tou druhou podminkou chceme zachytit pripady, kdy je v textu
// nekolik separatotu (napr. tecek) za sebou, pak to nebudeme povazovat za separator,
// ale jako vyznam k predchazejicimu slovu (vete).
// Navic pokud by takovy separator byl na konci oriznuteho textu, bude tak v podstate
// nahrazen volitelnym retezcem $append (defaultne trojtecka).
}
}
}
// pokud nenalezneme hledany pocet znaku, obsah je nejspis slozen ciste z HTML tagu
// (napr. flashova videa a jine medialni objekty)
if ($length >= $maxLen) {
$s = substr($s, 0, $i);
// uzavreme vsechny tagy
$enclosingTags = "";
if ($tags) {
$enclosingTags .= "</" . implode("></", $tags) . ">";
}
// Nyni potrebujeme probublat od konce pres vsechny tagy az na konec zobrazovaneho textu $s
// (tam pak budeme pridavat $append)
$s_beforeInnerEnclosingTags = $s;
$innerEnclosingTags = "";
while (substr(rtrim($s_beforeInnerEnclosingTags), - 1, 1) == ">") {
$innerEnclosingTags = strrchr($s_beforeInnerEnclosingTags, "<");
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, strlen($s_beforeInnerEnclosingTags) - strlen($innerEnclosingTags));
}
// Pokud je nastaven $append na trojtecku,
// orezeme jeste samotne tecky na konci rezce (pokud nejake jsou)
if ($append == iconv('UTF-8', 'windows-1250//TRANSLIT', "\xE2\x80\xA6")) {
$s_beforeInnerEnclosingTags = rtrim($s_beforeInnerEnclosingTags, '.');
}
// pokud byl nejaky separator nalezen
// a zaroven znak za zkracovanym textem neni separatorem
if (($pos > 0) && (!in_array(substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1), $separators))) {
// tak orizneme text za poslednim nalezenym separatorem
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, $pos);
}
// nebo take pokud byl nejaky separator nalezen
// a zaroven 2 znaky za zkracovanym textem jsou 2 stejne separatory (viz. * o neco vyse - stejny pripad)
else if (($pos > 0) && (in_array(substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1), $separators)) && ((substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1) == ((substr($INITAL_S, strlen($s_beforeInnerEnclosingTags) + 1, 1)))))) {
// tak orizneme text za poslednim nalezenym separatorem a dva vyse zminene ignorujeme
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, $pos);
}
// Nyni vse spojime dohromady a pripojime $append
$s = $s_beforeInnerEnclosingTags . $append . $innerEnclosingTags . $enclosingTags;
}
// Vystupni retezec prekodujeme zpet z windows-1250 do UTF-8
$s = iconv('windows-1250', 'UTF-8//TRANSLIT', $s);
}
return $s;
}
}
Do app/presenters/BasePresenter.php
jsem zaregistroval
helpery:
abstract class BasePresenter extends Presenter
{
public $oldLayoutMode = FALSE;
public $oldModuleMode = FALSE;
protected function beforeRender()
{
$this->template->registerHelper('xhtmlTruncate', array('MyString', 'xhtmlTruncate'));
$this->template->registerHelper('htmlTruncate', array('MyString', 'htmlTruncate'));
}
}
No a pak v sablonach (ted uz z vesela :-)) lze pouzivat:
{block content}
<div id="content">{!$newsItem->content|xhtmlTruncate:400}</div>
<!-- nebo -->
<div id="content">{!$newsItem->content|htmlTruncate:400}</div>
{/block}
Tak.. a je to, diky vsem za spolupraci a popostuchovani :-). Bylo by dobre, kdyby jste to otestovali a chyby pripadne napsali.
- Endrju
- Člen | 147
cuga napsal(a):
hoj, stalo se vam nekomu, ze vam to orezava prvni znak? mam zdrojovy texy v texy, ten prozenu parserem a na vyplivnute xHTML aplikuju truncate… akorat ze v nekterych pripadech mi to odrizne prvni pismeno… zkusim vysledovat nejaky duvod…
cuga napsal(a):
hlasi mi
<b>Notice</b>: Uninitialized string offset: 11 in <b>C:\xampp\htdocs\vs\libs\Extras\MyString.php</b> on line <b>98</b><br />
na radku je
if (($s[$i] != $s[$i+1]) && ($s[$i-1] != $s[$i])) {
Na Texy jsem to vubec nezkousel (zatim jsem ji nepotreboval). Je to testovano na CKEditoru a tam jsem problem neshledal. Pokud tam je nejaka chybka, zkus si tam dat breakponty a debugovat to, vysledovat, kde se ti ztrati nejaky znak atd.. Treba najdes v cem je problem. Jen upozornim, ze jako vstup je pozadovan string v UTF-8.
Co se tyka debugovani, tak by se ti hodilo nejake
IDE a pokud nemas tu moznost, tak by mozna pomohlo si v patricnych mistech
kodu dat Debug::dump($promenna);
coz ti vypise hodnotu te promenne
a zastavi kod v tom miste (nemylim-li se).
honzakuchar napsal(a):
Endrju napsal(a):
…Vypadá to dobře. Nechceš to přidat do extras? :-)
Pokud tam jsou nejake chyby, tak by to asi nebylo dobre, co :). Bohuzel ted a ani nasledujici mesic az dva nebudu mit cas (diplomka, statnice) hledat v cem je problem, pokud by jste to nekdo opravili mezititm, tak to bude super :).
A kdyz uz jsem u toho, tak jsem nedavno udelal drobnou upravu, ktera jeste vice optimalizuje zpracovani (nevim proc me to driv nenapadlo :))
Na prvnich dvou radcich v obou metodach (xhtmlTruncate()
a
htmlTruncate()
) nahradte tento kod:
// ma vubec smysl retezec zkracovat?
if (iconv_strlen($s, 'UTF-8') > $maxLen) {
Za tento kod:
// ma vubec smysl retezec zkracovat?
if (iconv_strlen(strip_tags($s), 'UTF-8') > $maxLen) {
Puvodne to kontrolovalo delku celeho stringu vcetne (x)HTML tagu a pripadne
nemuselo k fyzickemu zkraceni cisteho textu fubec dojit, ale funkce to stejne
cele musela zpracovat. Oprava zpusobi, ze se bude kontrolovat pouze zda onen
cisty text nepresahuje povolenou delku (tim ze se pri kontrole odstrani HTML
tagy) a kod se bude dal zpracovavat jen pokud cisty text je delsi nez maximalni
povolena delka.
Jeste me ted napadlo, ze by se ten text po odstraneni HTML znacek mohl trimnout
o bile znaky na zacatku a na konci. Tedy by to vypadlo takto:
// ma vubec smysl retezec zkracovat?
if (iconv_strlen(trim(strip_tags($s), 'UTF-8')) > $maxLen) {
Tohle ale nemam odzkouseno, tak nevim, zda by to nemohlo delat nejakou neplechu. Dovolim si ale tvrdit, ze by to bylo naprosto v poradku.
Editoval Endrju (16. 4. 2010 22:29)
- Quinix
- Člen | 108
cuga napsal(a):
hoj, stalo se vam nekomu, ze vam to orezava prvni znak? mam zdrojovy texy v texy, ten prozenu parserem a na vyplivnute xHTML aplikuju truncate… akorat ze v nekterych pripadech mi to odrizne prvni pismeno… zkusim vysledovat nejaky duvod…
Žraní znaků způsobuje tento kód:
<?php
$customWhitespaces = array("\0x09", "\0x0A", "\0x0D", "\0x00", "\0x0B");
foreach ($customWhitespaces AS $customWhitespace) {
$s = trim($s, $customWhitespace);
}
?>
Důvodem je nejspíš to, že řetězce v poli $customWhitespaces to bere
jako řetězec např. „\0×09“ a trim() pak odstraní vysloveně tyhle
znaky, čili i třeba A, B, D, pokud jsou na krajích textu.
Nevim, jestli jsem správně pochopil myšlenku toho kódu, ale pole by se mělo
imho nahradit něčím takovýmhle:
<?php
$customWhitespaces = array(chr(0x09),chr(0x0a),chr(0x0d),chr(0x00),chr(0x0b));
?>
Pak už to nic nežere :)
- aannubis
- Člen | 33
Narazil jsem na zajimavou chybu. Pokud mame treba takovyto kod
<p><strong>Text text text</strong><em>OPRAVDUHODNEDLOUHESLOVO</em></p>
a pokusime se ho zkratit treba na 15 znaku, tak implementace nezkracujici slova, se nam pokusi vratit Text text text. Ovsem tak jak je funkce napsana, se takto odstrani uzavreni znacky <strong> a zacatecni znacka <em>.
Zpusobuje to tento kod:
if (($pos > 0) && (!in_array(substr($INITAL_S, strlen($s_beforeInnerEnclosingTags), 1), $separators))) {
// tak orizneme text za poslednim nalezenym separatorem
$s_beforeInnerEnclosingTags = substr($s_beforeInnerEnclosingTags, 0, $pos);
}
Ten ma jako pozici posledniho separatoru ulozeno misto po poslednim slovu text, tam retezec orizne, avsak jako neuzavrene tagy ma ulozeno v tu chvili em a p, ale strong, ktery oriz uz ulozeny nema, takze ho neuzavre, a naopak uzavre em, ktery ovsem orizl, takze vznikne toto:
<p><strong>Text text text</em></p>
Nema autor jiz k dispozici nejakou opravu? Nevim moc ciste jako to opravit :(
Editoval aannubis (4. 5. 2011 18:13)