E' parecchio tempo che ci penso e volevo trovare un modo comodo per gestire le parole di una stringa. Per un uomo è facile capire cosa è una parola all'interno di una stringa, per un pc un pò meno visto che il concetto di "SPAZIO" inteso come bianco o no rappresenta nei vari linguaggi qualcosa di confusionario e fumoso. Penso sia capitato a tutti aver un testo lungo e volerne presentare una parte ai suoi utenti, magari corredata da un link [leggi tutto] per leggere il resto. Un esempio pratico è l'indice di alcuni articoli.
Un modo che sovraccarica poco il server e che evita troppi pensieri al programmatore sarebbe usare substr() e prendere un pezzetto della stringa, ma il rischio di troncare una parola è troppo alto ed in questo caso l'effetto è davvero pessimo.
L'altra idea sarebbe usare una split sugli spazi, ma immaginiamo che abbiamo una stringa le cui parole son separate da caratteri che non sono spazi? Che succede?
Per ovviare a questo problema ecco la mia pillola.
Le funzioni di cui faremo uso sono 3:
codice:
/* ### CONTA IL NUMERO DI PAROLE DI UNA STRINGA ### */
function wordsCounter($fStrWords){
$iTotalBlankSpaces=charCounter($fStrWords," ");
$iTotalCRLF=charCounter($fStrWords,"\n");
$iTotalHorTab=charCounter($fStrWords,"\t");
/* ### SI AGGIUNGE UNO PERCHE' IN REALTA' CONTIAMO I SEPARATORI E NON LE PAROLE ### */
$iTotalWords=$iTotalBlankSpaces + $iTotalCRLF + $iTotalHorTab+1;
return $iTotalWords;
}
/* ### CONTA IL NUMERO DI OCCORRENZE DEL CARATTERE ### */
function charCounter($fStrWords,$fCharTarget){
$arrOccurrences=count_chars($fStrWords,1);
$iAsciiCode=ord($fCharTarget);
if (isset($arrOccurrences[$iAsciiCode])){
$iOccurrences=$arrOccurrences[$iAsciiCode];
}else{
$iOccurrences=0;
}
return $iOccurrences;
}
/* ### SELEZIONA LE PRIME N PAROLE DALLA STRINGA ### */
function getWords($fStrWords,$fIntNumber){
$iEffWord=wordsCounter($fStrWords);
if ($iEffWord>$fIntNumber){
$fStrWords=str_replace("\n\r","\n",$fStrWords);
$fStrWords=str_replace("\r\n","\n",$fStrWords);
$fStrWords=str_replace("\r","\n",$fStrWords);
$arrWords=split("[ \t\n]",$fStrWords);
$strStoreSplitted="";
$strStoreJoined="";
for ($s=0;$s<$fIntNumber;$s++){
$strSplitted=$arrWords[$s];
$strStoreSplitted.=$strSplitted;
$iSeparatorPosition=strlen($strStoreSplitted)+$s;
$chrOldSeparator=substr($fStrWords,$iSeparatorPosition,1);
switch ($chrOldSeparator){
case "\t":
$chrNewSeparator="\t";
break;
case "\n":
$chrNewSeparator="\n";
break;
default :
$chrNewSeparator=" ";
break;
}
$strStoreJoined.= $strSplitted . $chrNewSeparator;
}
$strWords=$strStoreJoined . "...";
}else{
$strWords=$fStrWords;
}
return $strWords;
}
la funzione charCounter esegue un semplice conteggio di del carattere specificato come parametro e ne restituisce il numero di occorrenze. In questo caso è facile vedere che contiamo tutti i tipi di caratteri che possono modellare uno spazio. Io ho preso come esempio caratteri di newline, spazi bianchi e tab, ma se qualcuno avesse bisogno di considerarne altri può tranquillamente aggiungerne.
Da notare il parametro 1 nella funzione count_chars che evita che vengano restituiti nell'array i caratteri con occorrenza zero e quindi di sovraccaricare troppo la memoria.
Una volta conteggiati li sommiamo incrementando di uno il risultato perché ricordatevi che stiamo contanto i separatori e non le parole direttamente. Quindi tra due parole ci sarà un solo separatore.
Una cosa importantissima che devo far notare è che è indispensabile che alla funzione wordsCounter() venga passata una stringa pulita con trim() altrimenti il risultato non sarà preciso.
La funzione getWords() è invece il risultato che ci interessa maggiormente. Dopo aver contato le parole effettuamo una replace in modo da gestire meglio il concetto di A CAPO che in php è formato da due caratteri e non da uno solo. Evitando queste righe ho visto facendo un pò di prove che possiamo aver comportamenti imprevedibili.
A questo punto usiamo la funzione split con un espressione regolare. in questo caso: "[ \t\n]". Ovviamente questa espressione è direttamente collegata al tipo di carattere che vogliamo considerare come spazio. Come ho detto prima in questo esempio gli spazi sono gli spazi bianchi, i tab e gli a capo.
Una split in questo modo spezza la stringa ogni volta che incontra un carattere simile.
A questo punto dobbiamo ricomporre la stringa considerando le prime N parole (dove N è il secondo parametro) facendo però attenzione di ripristinare il vecchio separatore (se tra due parole c'è un tab, ci deve essere un tab anche nella stringa ricomposta, se no che macello combiniamo :P).
Fatto questo corrediamo la nostra stringa spezzata dai classici ... della tradizione e la restituiamo.
Ovviamente se la stringa ha meno parole di quelle da noi richieste sarà restituita intera e senza i puntini di sospensione!
Spero che la pillola sia utile a tutti coloro che vogliono aver un metodo immediato per presentare dei brani di testo (articoli, avvisi, news) in maniera semplice e senza cedere al compromesso degli spazi.