Wie kürze ich eine Zeichenfolge in PHP auf das Wort, das einer bestimmten Anzahl von Zeichen am nächsten kommt?

StackOverflow https://stackoverflow.com/questions/79960

  •  09-06-2019
  •  | 
  •  

Frage

Ich habe einen in PHP geschriebenen Codeausschnitt, der einen Textblock aus einer Datenbank abruft und ihn an ein Widget auf einer Webseite sendet.Der ursprüngliche Textblock kann ein längerer Artikel oder ein oder zwei kurze Sätze sein;aber für dieses Widget kann ich nicht mehr als, sagen wir, 200 Zeichen anzeigen.Ich könnte substr() verwenden, um den Text bei 200 Zeichen abzuschneiden, aber das Ergebnis wäre, dass er mitten im Wort abschneidet – was ich wirklich möchte, ist, den Text am Ende des letzten abzuschneiden Wort vor 200 Zeichen.

War es hilfreich?

Lösung

Durch die Verwendung der wordwrap Funktion. Es spaltet die Texte in mehreren Zeilen, so dass die maximale Breite diejenige, die Sie festgelegt ist, an Wortgrenzen zu brechen. Nach der Spaltung nehmen Sie einfach die erste Zeile:

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

Eine Sache, diese oneliner behandelt nicht der Fall ist, wenn der Text selbst kürzer als die gewünschte Breite ist. Um diesen Rand Fall zu behandeln, sollte man so etwas wie:

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

Die obige Lösung hat das Problem der vorzeitigen Schneiden Sie den Text, wenn es eine neue Zeile vor dem eigentlichen Trennwert enthält. Hier ist eine Version, die dieses Problem löst:

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));
}

Auch hier ist die PHPUnit Testklasse verwendet, um die Implementierung zu testen:

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));
  }
}

EDIT:

Spezielle UTF8-Zeichen wie ‚a‘ nicht behandelt werden. Add ‚u‘ am Ende des REGEX es zu handhaben:

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

Andere Tipps

Damit werden die ersten 200 Zeichen der Worte zurück:

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

Und dort haben Sie es - eine zuverlässige Methode beliebige Zeichenfolge auf die nächste ganze Wort abgeschnitten wird, während sie unter der maximalen String-Länge des Aufenthaltes

.

Ich habe die anderen Beispiele versucht, oben, und sie haben nicht die gewünschten Ergebnisse produzieren.

Die folgende Lösung wurde geboren, als ich einen $ Pause Parameter bemerkt haben wordwrap Funktion:

  

string wordwrap (string $ str [, int $ width = 75 [, string $ Pause =   "\ N" [, bool $ cut = false]]])

Hier die Lösung :

/**
 * 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");
}

Beispiel # 1.

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

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

This is very long string...

Beispiel # 2.

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

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

This is short string.

Denken Sie bei der Aufteilung nach „Wort“ daran, dass einige Sprachen wie Chinesisch und Japanisch kein Leerzeichen zum Aufteilen von Wörtern verwenden.Außerdem könnte ein böswilliger Benutzer einfach Text ohne Leerzeichen eingeben oder ein Unicode-ähnliches Zeichen zum Standard-Leerzeichen verwenden. In diesem Fall könnte jede von Ihnen verwendete Lösung dazu führen, dass am Ende trotzdem der gesamte Text angezeigt wird.Eine Möglichkeit, dies zu umgehen, besteht darin, die Zeichenfolgenlänge zu überprüfen, nachdem sie wie gewohnt in Leerzeichen aufgeteilt wurde. Wenn die Zeichenfolge dann immer noch über einem abnormalen Grenzwert liegt – in diesem Fall vielleicht 225 Zeichen –, teilen Sie sie einfach an diesem Grenzwert auf.

Noch eine Einschränkung bei solchen Dingen, wenn es um Nicht-ASCII-Zeichen geht;Zeichenfolgen, die sie enthalten, werden möglicherweise von PHPs Standard strlen() als länger interpretiert, als sie tatsächlich sind, da ein einzelnes Zeichen möglicherweise zwei oder mehr Bytes anstelle nur eines benötigt.Wenn Sie nur die Funktionen strlen()/substr() zum Teilen von Zeichenfolgen verwenden, teilen Sie möglicherweise eine Zeichenfolge in der Mitte eines Zeichens!Im Zweifel, mb_strlen()/mb_substr() sind etwas narrensicherer.

Mit strpos und 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;

Dies gibt Ihnen eine Zeichenfolge am ersten Leerzeichen abgeschnitten nach 30 Zeichen.

Hier ist meine Funktion basiert auf @ Cd-MaN Ansatz.

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

  return $string;
}

Hier gehen Sie:

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;
   }
}

Es ist erstaunlich, wie schwierig es ist, die perfekte Lösung für dieses Problem zu finden. Ich habe noch keine Antwort auf dieser Seite gefunden, die zumindest in einigen Situationen nicht scheitern (vor allem, wenn die Zeichenfolge Zeilenumbrüche oder Tabulatoren enthält, oder wenn der Wortbruch ist etwas anderes als ein Raum, oder wenn die Zeichenfolge hat UTF- 8 Mehrbytezeichen).

Hier ist eine einfache Lösung, die in allen Fällen funktioniert. Es gab ähnliche Antworten hier, aber das „s“ Modifikator ist wichtig, wenn Sie es wollen mit Eingabe mit mehreren Leitungen arbeiten, und das „u“ Modifikator macht es UTF-8 Mehrbytezeichen korrekt zu bewerten.

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

Eine mögliche Kante Fall mit diesem ..., wenn die Zeichenfolge keine Leerzeichen haben überhaupt in den ersten $ characterCount Zeichen, es wird die gesamte Zeichenfolge zurück. Wenn Sie lieber eine Pause bei $ characterCount zwingt, auch wenn es keine Wortgrenze ist, können Sie diese verwenden:

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

Eine letzte Option, wenn Sie wollen es Ellipsen haben hinzuzufügen, wenn die Zeichenfolge abschneidet ...

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;
}
$shorttext = preg_replace('/^([\s\S]{1,200})[\s]+?[\s\S]+/', '$1', $fulltext);

Beschreibung:

  • ^ - ab Beginn der Zeichenfolge
  • ([\s\S]{1,200}) - erhalten 1-200 von einem beliebigen Zeichen
  • [\s]+? - keine Leerzeichen am Ende des kurzen Textes an, damit wir word ... statt word...
  • vermeiden
  • [\s\S]+ - entsprechen alle anderen Inhalte

Tests:

  1. regex101.com lassen Sie uns einige andere or r hinzufügen
  2. regex101.com orrrr genau 200 Zeichen.
  3. regex101.com nach fünftem r orrrrr ausgeschlossen.

Genießen.

Ich würde die preg_match Funktion verwenden, um dies zu tun, als das, was Sie wollen ein ziemlich einfacher Ausdruck ist.

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

Der Ausdruck bedeutet „jede Teilkette entsprechen, ausgehend von dem Beginn der Länge 1-200, die mit einem Zwischenraum endet.“ Das Ergebnis ist in $ result, und das Spiel ist in $ matches. Das kümmert sich um Ihre ursprüngliche Frage, die speziell auf jedem Platz endet. Wenn Sie wollen, dass es auf Zeilenumbrüche machen zu beenden, den regulären Ausdruck ändern:

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

Ok, so habe ich eine andere Version davon auf der Grundlage der oben genannten Antworten aber mehr Dinge in Rechnung zu tragen (utf-8, \ n und & nbsp;), auch eine Linie, die die Wordpress Shortcodes Strippen, wenn mit wp verwendet kommentiert

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;
  }
/*
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);
}

Verbrauch:

$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); 

Dies wird Ausgangs ersten 10 Wörter.

Die preg_split Funktion wird verwendet, um eine Zeichenfolge in Teil aufzuspalten. Die Grenzen, entlang denen die Zeichenfolge aufgeteilt werden, sind ein reguläres Ausdrücke Muster angegeben ist.

preg_split Funktion nimmt vier Parameter, sondern nur die ersten 3 sind relevant für uns jetzt.

Der erste Parameter - Muster Der erste Parameter ist die reguläre Ausdrücke Muster, entlang dem die Zeichenfolge aufgeteilt werden soll. In unserem Fall wollen wir die Zeichenfolge über Wortgrenzen teilen. Deshalb verwenden wir eine vordefinierte Zeichenklasse \s die Leerzeichen wie Raum passt, Tab, Wagenrücklauf und Zeilenvorschub.

Zweiter Parameter - Eingabestring Der zweite Parameter ist die lange Textzeichenfolge, die wir teilen möchten.

Dritte Parameter - Limit Der dritte Parameter spezifiziert die Anzahl der Teilstrings, die zurückgeführt werden sollen. Wenn Sie die Grenze n gesetzt, preg_split wird ein Array von n Elementen zurück. Die ersten n-1 Elemente werden die Zeichenketten enthalten. Das letzte (n th) Element wird den Rest der Zeichenfolge enthalten.

Basierend auf @Justin Poliey regex:

// 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]. '...';
}

Dies ist ein kleines Update für mattmac Antwort:

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

Der einzige Unterschied ist, einen Raum am Ende $ string hinzuzufügen. Dies stellt sicher, das letzte Wort nicht als pro ReX357 Kommentar abgeschnitten.

Ich habe nicht genug rep Punkte dies als Kommentar hinzuzufügen.

Ich habe eine Funktion, die fast nicht, was Sie wollen, wenn Sie ein paar Änderungen tun werden, sie paßt genau:

<?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;
}
?>

Das ist, wie ich es tat:

$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")));

Ich weiß, das ist alt, aber ...

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

Ich habe diese vor

<?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;
?>

ich eine Funktion ähnliche substr, und mit der Idee von @ 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 .: Die volle Länge geschnitten geringer sein kann als substr.

hinzugefügt IF / ELSEIF-Anweisungen, um den Code von Dave und AmalMurali Umgang mit Strings ohne Leerzeichen

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);
}

Ich glaube, das ist der einfachste Weg, es zu tun:

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

Ich verwende die Sonderzeichen, den Text zu spalten und schneiden Sie es.

Ich finde, das funktioniert:

Funktion abbreviate_string_to_whole_word ($ string, $ 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;

}

Der Puffer können Sie die Länge der zurückgegebenen Zeichenfolge einzustellen.

verwenden:

Mit dem folgenden Code wird entfernen ''. Wenn Sie anyother Zeichen oder Unterkette haben, können Sie, dass anstelle der Verwendung ‚‘

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

// Wenn Sie eine andere Zeichenfolge Konto für

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

Hier können Sie versuchen, diese

substr( $str, 0, strpos($str, ' ', 200) ); 

Kann dies jemand helfen:

<?php

    $string = "Your line of text";
    $spl = preg_match("/([, \.\d\-''\"\"_()]*\w+[, \.\d\-''\"\"_()]*){50}/", $string, $matches);
    if (isset($matches[0])) {
        $matches[0] .= "...";
        echo "<br />" . $matches[0];
    } else {
        echo "<br />" . $string;
    }

?>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top