A weblaboron merült fel egy kérdés: hogyan lehet szépen megoldani, hogy egy hosszú szövegből előállítsunk egy rövidebb bevezetőt, aminek korlátozva van a maximális hossza, és szóhatárnál végződik. Itt adok rá egy megoldást.
Először is a megoldás: RegExp.
1 | \A(.{0,60})\b |
Ez a RegExp a következőt jelenti: vegyünk egy 0 és 60 karakter hosszú (rész)sztringet (.{0, 60}), amely az eredeti sztring elején kezdődik (\A) és szóhatárnál végződik (\b). A RegExp motor ezt többnyire elég gyorsan meg fogja találni, mivel mohón keresi, tehát a 60. karaktertől elindul visszafelé, és megkeresi a legelső karaktert, amely után szóhatár van (szóhatár alatt szó kezdetet és véget egyaránt értünk). Az első probléma ezzel, hogy szóközre (pontosabban white-space karakterre) végződő sztringet is kaphatunk (szó kezdet eset), úgyhogy ezt a kódból kezelnünk kell majd.
Írjunk is köré egy wrappert:
1 2 3 4 5 6 7 8 | <?php function intro($string, $maxLength = 30, $template = '%1$s') { if (preg_match(sprintf('/\A(.{0,%d})\b/si', $maxLength), $string, $result)) { return sprintf($template, rtrim($result[0])); } return ''; } |
Végülis ennyi a függvény: dinamikusan beszúrjuk a kívánt maximális hosszt a fenti reguláris kifejezésbe, aztán ráeresztjük a sztringre, majd a kapott stringet behelyettesítjük a(z opcionálisan megadható) sablonba.
Példa a használatára:
1 | echo intro('Árvíztűrő tükörfúrógép, asdasd és foobar foo baz bar illetve lorem ipsum', 30, '%1$s ...'); |
És a kiemenet:
Árvíztűrő tükörfúrógép, asdasd ...
http://www.php.net/sprintf
Az ott nem l (kis L), hanem 1 (egy, szám). Amúgy azt jelenti, hogy az első paraméter (1) sztringként (s) kerüljön oda.
BlackY
a %l$s a templatenel mit jelent? ;]
Sziasztok!
És mit kellene akkor csinálni, ha ez a szöveg tele van formázásokkal?
Hogy tudnám a html-t text-é alakítani?
Köszönjük ezt a kis script-et :)
Erre tökéletesen bevált recept nincs (mármint a markup-mentesítésre), viszont bevezetőt főleg olyan dolgokhoz szokás csinálni, amit admin felületen raksz fel és nem a userek küldenek be, egy strip_tags bőven elég (ha meg usertől származik az adat, amiről készül a bevezető, akkor keresel google-vel egy „remove html regexp”-et és kapsz pár találatot).
Így a teljes hívás:
BlackY
Én ezt a függvény használom a html formázások eltávolítására:
function html2text($dokumentum) {
$mit = array („‘<script[^.*?’si”,
„‘<[\/\!]*?[^]*?>’si”,
„‘([\r\n])[\s]+'”,
„‘&(quot|#34);’i”,
„‘&(amp|#38);’i”,
„‘&(lt|#60);’i”,
„‘&(gt|#62);’i”,
„‘&(nbsp|#160);’i”,
„‘&(iexcl|#161);’i”,
„‘&(cent|#162);’i”,
„‘&(pound|#163);’i”,
„‘&(copy|#169);’i”,
„‘&#(\d+);’e”);
$mire = array („”,
„”,
” „,
„\””,
„&”,
„”,
” „,
chr(161),
chr(162),
chr(163),
chr(169),
„chr(\\1)”);
return htmlspecialchars(preg_replace ($mit, $mire, $dokumentum));
}
Köszönjük eme függvényt, pofás és kicsi. Teljesen jól használható, ajánlom mindenki figyelmébe.
Blacky! Ennek meg tudnád írni az Unicode karaktereket is támogató verzióját?
Ha a preg_match-nél beadod még az u kapcsolót (tehát a vége /si helyett /usi), akkor már azzal is működni fog.
BlackY
Úgy próbáltam én is, de nem működött. Az unicode karakternél vette a szó végét és ott vágta el, meg hasonlók. Próbáld ki!
És tényleg…
Viszont ha a \b (szóhatárt) lecseréled egy (\s|\Z) (whitespace karakter vagy sor/input vége), akkor ugyanazt a működést kéne kapnod. Cserébe ezzel vannak csúnya esetek, amik a sima szóhatárnál nincsenek:
Pl.: ha írásjelre végződik a kapott rész, akkor hülyén néz ki, hogy a levágott szöveged ilyen: „Árvíztűrő tükörfúrógép,”, pont-kérdőjel-felkiáltójelnél ez még jól is jönne, de így. A trim-be mondjuk fel lehetne venni a karaktereket, amik hülyén néznek ki egy bevezető szöveg végén, csak szép hosszú lenne a lista.
Azt lehetne csinálni, hogy a . helyett felsorolod a magyar betűket, a \b-t lecseréled egy negative lookahead-re (^([A-Záéűúőóüö]{0,30})(?![A-Záéűúőóüö])), az viszont nem csúnyán néz ki.
BlackY
Egy kicsit módosítva…
Kicsit módosítva…
************************************
function intro($string, $maxLength = 30, $template = ‘%1$s’)
{ //formázás kivétele a szövegből
$string = strip_tags($string);
//módosított reguláris kifejezés
$format=’/\A(.{0,%d})[\s]\b/siu’;
if (preg_match(sprintf($format, $maxLength), $string, $result)) {
//if (preg_match(sprintf(‘/\A(.{0,%d})\b/si’, $maxLength), $string, $result)) {
return sprintf($template, rtrim($result[0]));
}
return ”;
}
*************************
function strcut($text,$length,$dots=true)
{
if (preg_match(‘/^(.{0,’ . $length . ‘})(?:,|;|\.|\?|!|\s|$)/su’,$text,$matches)) return $matches[1] . ($dots && strlen($matches[1])<strlen($text) ? ' …' : '');
else return;
}
Nekem „lnorby” megoldása tökéletesen működik, viszont a vesszőre (,) vegződő vágott sztringeket elég csúnyán jeleníti meg (asdasd,…), s egyenlőre nem találtam rá megoldást (sajnos annyire nem értek még a Regexhez). :( Van esetleg valami ötlet?
És így?
function strcut($string,$maxLength,$dots=true)
{
if(preg_match(‘/^(.{0,’ . $maxLength . ‘})(?:,|;|\.|\?|!|\s|$)/su’,$string,$matches))
//return $matches[1] . ($dots && strlen($matches[1])<strlen($string) ? ' …' : '');
return str_replace(",", "", $matches[1]).($dots && strlen($matches[1])<strlen($string) ? ' …' : '');
else
return;
}
Ha csak az utolsót(a pontok előttit), akkor
return substr_replace($matches[1], ”, strlen($matches[1])-1, 1).($dots && strlen($matches[1])<strlen($string) ? '…' : '');
Mit szólsz az „rtrim”-hez? (Igen, csak a pontok előtti vessző nem kell…)