it-swarm.it

Come troncare una stringa in PHP alla Parola più vicina a un certo numero di personaggi?

Ho uno snippet di codice scritto in PHP che estrae un blocco di testo da un database e lo invia a un widget su una pagina web. Il blocco di testo originale può essere un lungo articolo o una breve frase o due; ma per questo widget non posso visualizzare più di, diciamo, 200 caratteri. Potrei usare substr () per tagliare il testo a 200 caratteri, ma il risultato sarebbe interrotto nel mezzo di parole-- quello che voglio veramente è tagliare il testo alla fine dell'ultimo Parola prima di 200 caratteri.

170
Brian

Usando la funzione wordwrap . Divide i testi in più righe in modo tale che la larghezza massima sia quella specificata, superando i confini della Parola. Dopo la divisione, si prende semplicemente la prima riga:

substr($string, 0, strpos(wordwrap($string, $your_desired_width), "\n"));

Una cosa che questo oneliner non gestisce è il caso in cui il testo stesso è più corto della larghezza desiderata. Per gestire questo caso Edge, si dovrebbe fare qualcosa come:

if (strlen($string) > $your_desired_width) 
{
    $string = wordwrap($string, $your_desired_width);
    $string = substr($string, 0, strpos($string, "\n"));
}

La soluzione di cui sopra ha il problema di tagliare prematuramente il testo se contiene una nuova riga prima del punto di divisione effettivo. Ecco una versione che risolve questo problema:

function tokenTruncate($string, $your_desired_width) {
  $parts = preg_split('/([\s\n\r]+)/', $string, null, PREG_SPLIT_DELIM_CAPTURE);
  $parts_count = count($parts);

  $length = 0;
  $last_part = 0;
  for (; $last_part < $parts_count; ++$last_part) {
    $length += strlen($parts[$last_part]);
    if ($length > $your_desired_width) { break; }
  }

  return implode(array_slice($parts, 0, $last_part));
}

Inoltre, ecco la classe di test PHPUnit utilizzata per testare l'implementazione:

class TokenTruncateTest extends PHPUnit_Framework_TestCase {
  public function testBasic() {
    $this->assertEquals("1 3 5 7 9 ",
      tokenTruncate("1 3 5 7 9 11 14", 10));
  }

  public function testEmptyString() {
    $this->assertEquals("",
      tokenTruncate("", 10));
  }

  public function testShortString() {
    $this->assertEquals("1 3",
      tokenTruncate("1 3", 10));
  }

  public function testStringTooLong() {
    $this->assertEquals("",
      tokenTruncate("toooooooooooolooooong", 10));
  }

  public function testContainingNewline() {
    $this->assertEquals("1 3\n5 7 9 ",
      tokenTruncate("1 3\n5 7 9 11 14", 10));
  }
}

MODIFICARE :

I caratteri speciali UTF8 come 'à' non vengono gestiti. Aggiungi "u" alla fine di REGEX per gestirlo:

$parts = preg_split('/([\s\n\r]+)/u', $string, null, PREG_SPLIT_DELIM_CAPTURE);

212
Grey Panther

Ciò restituirà i primi 200 caratteri di parole:

preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, 201));
125
mattmac
$WidgetText = substr($string, 0, strrpos(substr($string, 0, 200), ' '));

E lì ce l'hai - un metodo affidabile per troncare qualsiasi stringa alla parola intera più vicina, pur restando sotto la lunghezza massima della stringa.

Ho provato gli altri esempi sopra e non hanno prodotto i risultati desiderati.

42
Dave

La seguente soluzione è nata quando ho notato un parametro $ break di wordwrap function:

stringa wordwrap (stringa $ str [ int $ larghezza = 75 [ stringa $ break = "\ n" [ bool $ cut = false]]])

Ecco la soluzione:

/**
 * Truncates the given string at the specified length.
 *
 * @param string $str The input string.
 * @param int $width The number of chars at which the string will be truncated.
 * @return string
 */
function truncate($str, $width) {
    return strtok(wordwrap($str, $width, "...\n"), "\n");
}

Esempio 1.

print truncate("This is very long string with many chars.", 25);

L'esempio sopra mostrerà:

This is very long string...

Esempio # 2.

print truncate("This is short string.", 25);

L'esempio sopra mostrerà:

This is short string.
33
Sergiy Sokolenko

Tieni presente ogni volta che dividi "Parola" ovunque che alcune lingue come il cinese e il giapponese non utilizzano un carattere di spazio per suddividere le parole. Inoltre, un utente malintenzionato potrebbe semplicemente inserire del testo senza spazi o utilizzare un Unicode simile al carattere dello spazio standard, nel qual caso qualsiasi soluzione che si utilizza potrebbe finire per visualizzare comunque l'intero testo. Un modo per aggirare questo potrebbe essere quello di controllare la lunghezza della stringa dopo averla divisa in spazi normali, quindi, se la stringa è ancora al di sopra di un limite anormale - forse 225 caratteri in questo caso - andare avanti e dividerlo in modo stupido a quel limite.

Ancora un avvertimento con cose come questa quando si tratta di caratteri non ASCII; le stringhe che le contengono possono essere interpretate dallo strlen () standard di PHP come più lungo di quello che realmente sono, perché un singolo carattere può richiedere due o più byte invece di uno solo. Se si utilizzano semplicemente le funzioni strlen ()/substr () per dividere le stringhe, è possibile dividere una stringa nel mezzo di un carattere! In caso di dubbi, mb_strlen () / mb_substr () sono un po 'più infallibili.

9
Garrett Albright

Usa strpos e substr:

<?php

$longString = "I have a code snippet written in PHP that pulls a block of text.";
$truncated = substr($longString,0,strpos($longString,' ',30));

echo $truncated;

Questo ti darà una stringa troncata nel primo spazio dopo 30 caratteri.

8
Lucas Oman

Ecco la mia funzione basata sull'approccio di @ Cd-MaN.

function shorten($string, $width) {
  if(strlen($string) > $width) {
    $string = wordwrap($string, $width);
    $string = substr($string, 0, strpos($string, "\n"));
  }

  return $string;
}
5
Camsoft

Ecco qui:

function neat_trim($str, $n, $delim='…') {
   $len = strlen($str);
   if ($len > $n) {
       preg_match('/(.{' . $n . '}.*?)\b/', $str, $matches);
       return rtrim($matches[1]) . $delim;
   }
   else {
       return $str;
   }
}
4
UnkwnTech

È sorprendente quanto sia complicato trovare la soluzione perfetta a questo problema. Non ho ancora trovato una risposta in questa pagina che non fallisca in almeno alcune situazioni (specialmente se la stringa contiene newlines o tabs, o se l'interruzione di Word è qualcosa di diverso da uno spazio, o se la stringa ha UTF- 8 caratteri multibyte).

Ecco una soluzione semplice che funziona in tutti i casi. C'erano risposte simili qui, ma il modificatore "s" è importante se vuoi che funzioni con l'input su più righe, e il modificatore "u" rende correttamente valutare i caratteri multibyte UTF-8.

function wholeWordTruncate($s, $characterCount) 
{
    if (preg_match("/^.{1,$characterCount}\b/su", $s, $match)) return $match[0];
    return $s;
}

Un possibile caso Edge con questo ... se la stringa non ha spazi bianchi nei primi caratteri $ characterCount, restituirà l'intera stringa. Se preferisci, impone una pausa a $ characterCount anche se non è un limite di Word, puoi usare questo:

function wholeWordTruncate($s, $characterCount) 
{
    if (preg_match("/^.{1,$characterCount}\b/su", $s, $match)) return $match[0];
    return mb_substr($return, 0, $characterCount);
}

Un'ultima opzione, se vuoi aggiungerla, Ellipsis se tronca la stringa ... 

function wholeWordTruncate($s, $characterCount, $addEllipsis = ' …') 
{
    $return = $s;
    if (preg_match("/^.{1,$characterCount}\b/su", $s, $match)) 
        $return = $match[0];
    else
        $return = mb_substr($return, 0, $characterCount);
    if (strlen($s) > strlen($return)) $return .= $addEllipsis;
    return $return;
}
3
orrd
$shorttext = preg_replace('/^([\s\S]{1,200})[\s]+?[\s\S]+/', '$1', $fulltext);

Descrizione:

  • ^ - inizia dall'inizio della stringa
  • ([\s\S]{1,200}): ottieni da 1 a 200 di qualsiasi carattere
  • [\s]+? - non includere spazi alla fine del breve testo in modo da evitare Word ... anziché Word...
  • [\s\S]+ - corrisponde a tutti gli altri contenuti

Test:

  1. regex101.com aggiungiamo a or pochi altri r
  2. regex101.comorrrr esattamente 200 caratteri.
  3. regex101.com dopo quinto rorrrrr escluso.

Godere.

3
hlcs

Ok, quindi ho ottenuto un'altra versione di questo basato sulle risposte di cui sopra, ma prendendo più cose in considerazione (utf-8,\n e & nbsp;), anche una riga che elimina gli shortcode wordpress commentati se usati con wp.

function neatest_trim($content, $chars) 
  if (strlen($content) > $chars) 
  {
    $content = str_replace('&nbsp;', ' ', $content);
    $content = str_replace("\n", '', $content);
    // use with wordpress    
    //$content = strip_tags(strip_shortcodes(trim($content)));
    $content = strip_tags(trim($content));
    $content = preg_replace('/\s+?(\S+)?$/', '', mb_substr($content, 0, $chars));

    $content = trim($content) . '...';
    return $content;
  }
2
Yo-L
/*
Cut the string without breaking any words, UTF-8 aware 
* param string $str The text string to split
* param integer $start The start position, defaults to 0
* param integer $words The number of words to extract, defaults to 15
*/
function wordCutString($str, $start = 0, $words = 15 ) {
    $arr = preg_split("/[\s]+/",  $str, $words+1);
    $arr = array_slice($arr, $start, $words);
    return join(' ', $arr);
}

Uso:

$input = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna liqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';
echo wordCutString($input, 0, 10); 

Questo produrrà le prime 10 parole.

La funzione preg_split viene utilizzata per suddividere una stringa in sottostringhe. I confini lungo i quali la stringa deve essere divisa, vengono specificati utilizzando un modello di espressioni regolari.

La funzione preg_split richiede 4 parametri, ma solo i primi 3 sono rilevanti per noi al momento.

Primo parametro - Modello Il primo parametro è il modello di espressioni regolari lungo il quale la stringa deve essere divisa. Nel nostro caso, vogliamo dividere la stringa tra i confini di Word. Pertanto utilizziamo una classe di caratteri predefinita \s che corrisponde a caratteri dello spazio bianco come spazio, tabulazione, ritorno a capo e avanzamento riga.

Secondo parametro - Input String Il secondo parametro è la stringa di testo lunga che vogliamo dividere.

Terzo parametro - Limite Il terzo parametro specifica il numero di sottostringhe da restituire. Se imposti il ​​limite su n, preg_split restituirà un array di n elementi. I primi elementi n-1 conterranno le sottostringhe. L'ultimo elemento (n th) conterrà il resto della stringa.

2
bodi0

Vorrei usare la funzione preg_match per fare ciò, poiché ciò che vuoi è un'espressione piuttosto semplice.

$matches = array();
$result = preg_match("/^(.{1,199})[\s]/i", $text, $matches);

L'espressione significa "abbinare qualsiasi sottostringa a partire dall'inizio della lunghezza 1-200 che termina con uno spazio". Il risultato è in $ result e la partita è in $ matches. Questo si prende cura della tua domanda originale, che si conclude specificamente su qualsiasi spazio. Se vuoi farlo finire su newline, cambia l'espressione regolare in:

$result = preg_match("/^(.{1,199})[\n]/i", $text, $matches);
2
Justin Poliey

Ecco come l'ho fatto:

$string = "I appreciate your service & idea to provide the branded toys at a fair rent price. This is really a wonderful to watch the kid not just playing with variety of toys but learning faster compare to the other kids who are not using the BooksandBeyond service. We wish you all the best";

print_r(substr($string, 0, strpos(wordwrap($string, 250), "\n")));
1
Shashank Saxena

Ho una funzione che fa quasi quello che vuoi, se farai qualche modifica, si adatterà esattamente:

<?php
function stripByWords($string,$length,$delimiter = '<br>') {
    $words_array = explode(" ",$string);
    $strlen = 0;
    $return = '';
    foreach($words_array as $Word) {
        $strlen += mb_strlen($Word,'utf8');
        $return .= $Word." ";
        if($strlen >= $length) {
            $strlen = 0;
            $return .= $delimiter;
        }
    }
    return $return;
}
?>
1
Rikudou_Sennin

Basato sulla regex di @Justin Poliey:

// Trim very long text to 120 characters. Add an Ellipsis if the text is trimmed.
if(strlen($very_long_text) > 120) {
  $matches = array();
  preg_match("/^(.{1,120})[\s]/i", $very_long_text, $matches);
  $trimmed_text = $matches[0]. '...';
}
1
amateur barista

Questa è una piccola correzione per la risposta di mattmac:

preg_replace('/\s+?(\S+)?$/', '', substr($string . ' ', 0, 201));

L'unica differenza è aggiungere uno spazio alla fine di $ stringa. Ciò garantisce che l'ultima parola non venga troncata come da commento di ReX357.

Non ho abbastanza punti rep per aggiungere questo come commento.

1
tanc

Aggiunte istruzioni IF/ELSEIF al codice da Dave e AmalMurali per la gestione di stringhe senza spazi

if ((strpos($string, ' ') !== false) && (strlen($string) > 200)) { 
    $WidgetText = substr($string, 0, strrpos(substr($string, 0, 200), ' ')); 
} 
elseif (strlen($string) > 200) {
    $WidgetText = substr($string, 0, 200);
}
0
jdorenbush

So che è vecchio, ma ...

function _truncate($str, $limit) {
    if(strlen($str) < $limit)
        return $str;
    $uid = uniqid();
    return array_shift(explode($uid, wordwrap($str, $limit, $uid)));
}
0
gosukiwi

Creo una funzione più simile a substr e utilizzo l'idea di @Dave.

function substr_full_Word($str, $start, $end){
    $pos_ini = ($start == 0) ? $start : stripos(substr($str, $start, $end), ' ') + $start;
    if(strlen($str) > $end){ $pos_end = strrpos(substr($str, 0, ($end + 1)), ' '); } // IF STRING SIZE IS LESSER THAN END
    if(empty($pos_end)){ $pos_end = $end; } // FALLBACK
    return substr($str, $pos_ini, $pos_end);
}

Ps .: il taglio a tutta lunghezza può essere inferiore al substr.

0
evandro777

Credo che questo sia il modo più semplice per farlo:

$lines = explode('♦♣♠',wordwrap($string, $length, '♦♣♠'));
$newstring = $lines[0] . ' &bull; &bull; &bull;';

Sto usando i caratteri speciali per dividere il testo e tagliarlo.

0
Namida

L'ho usato prima

<?php
    $your_desired_width = 200;
    $string = $var->content;
    if (strlen($string) > $your_desired_width) {
        $string = wordwrap($string, $your_desired_width);
        $string = substr($string, 0, strpos($string, "\n")) . " More...";
    }
    echo $string;
?>
0
Yousef Altaf

Trovo questo funziona:

function abbreviate_string_to_whole_Word ($ stringa, $ max_length, $ buffer) {

if (strlen($string)>$max_length) {
    $string_cropped=substr($string,0,$max_length-$buffer);
    $last_space=strrpos($string_cropped, " ");
    if ($last_space>0) {
        $string_cropped=substr($string_cropped,0,$last_space);
    }
    $abbreviated_string=$string_cropped."&nbsp;...";
}
else {
    $abbreviated_string=$string;
}

return $abbreviated_string;

}

Il buffer consente di regolare la lunghezza della stringa restituita.

0
Mat Barnett

Usa questo: 

il seguente codice rimuoverà ','. Se hai qualche altro carattere o sottostringa, puoi usare quello invece di ","

substr($string, 0, strrpos(substr($string, 0, $comparingLength), ','))

// se hai un altro account stringa per 

substr($string, 0, strrpos(substr($string, 0, $comparingLength-strlen($currentString)), ','))
0
Mahbub Alam