it-swarm-eu.dev

So schneiden Sie eine Zeichenfolge ab PHP zu dem Wort, das einer bestimmten Anzahl von Zeichen am nächsten kommt?

Ich habe ein in PHP geschriebenes Code-Snippet, das einen Textblock aus einer Datenbank abruft und an ein Widget auf einer Webseite sendet. Der ursprüngliche Textblock kann ein langer Artikel oder ein oder zwei kurze Sätze sein. Für dieses Widget kann ich jedoch nicht mehr als 200 Zeichen anzeigen. Ich könnte substr () verwenden, um den Text bei 200 Zeichen abzuschneiden, aber das Ergebnis würde sich in der Mitte der Wörter abschneiden Wort vor 200 Zeichen.

170
Brian

Mit der Funktion Zeilenumbruch . Die Texte werden in mehrere Zeilen aufgeteilt, sodass die maximale Breite der von Ihnen angegebenen entspricht und an den Word-Grenzen unterbrochen wird. Nach dem Teilen nehmen Sie einfach die erste Zeile:

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

Eine Sache, die dieser Oneliner nicht behandelt, ist der Fall, wenn der Text selbst kürzer als die gewünschte Breite ist. Um mit diesem Edge-Fall umzugehen, sollte man etwas machen 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, den Text vorzeitig auszuschneiden, wenn er eine neue Zeile vor dem eigentlichen Schnittpunkt enthält. Hier 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));
}

Hier ist auch die PHPUnit-Testklasse, die zum Testen der Implementierung verwendet wird:

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 'à' werden nicht behandelt. Füge 'u' am Ende des REGEX hinzu, um damit umzugehen:

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

214
Grey Panther

Dadurch werden die ersten 200 Zeichen der Wörter zurückgegeben:

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

Und da haben Sie es - eine zuverlässige Methode, um jeden String auf das nächste ganze Word zu kürzen, während die maximale Stringlänge unterschritten wird.

Ich habe die anderen Beispiele oben ausprobiert und sie haben nicht die gewünschten Ergebnisse erzielt.

42
Dave

Die folgende Lösung wurde geboren, als ich einen $ break-Parameter der wordwrap - Funktion bemerkte:

zeichenkettenumbruch (Zeichenfolge $ str [ int $ width = 75 [ Zeichenfolge $ break = "\ n" [ bool $ cut = false]]])

Hier ist 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 obige Beispiel gibt Folgendes aus:

This is very long string...

Beispiel # 2.

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

Das obige Beispiel gibt Folgendes aus:

This is short string.
33

Denken Sie immer daran, wenn Sie nach "Word" überall aufteilen, dass einige Sprachen wie Chinesisch und Japanisch kein Leerzeichen verwenden, um Wörter zu teilen. Ein böswilliger Benutzer könnte auch einfach Text ohne Leerzeichen eingeben oder ein Unicode-ähnliches Zeichen wie das Standard-Leerzeichen verwenden. In diesem Fall kann es vorkommen, dass bei jeder von Ihnen verwendeten Lösung ohnehin der gesamte Text angezeigt wird. Eine Möglichkeit, dies zu umgehen, besteht darin, die Länge der Zeichenfolge zu überprüfen, nachdem sie wie üblich in Leerzeichen aufgeteilt wurde. Wenn die Zeichenfolge immer noch über einem anormalen Grenzwert liegt (in diesem Fall vielleicht 225 Zeichen), wird der String bei diesem Grenzwert vorgespalten.

Ein weiterer Vorbehalt bei solchen Dingen bei Nicht-ASCII-Zeichen; Zeichenfolgen, die sie enthalten, können von PHP standardmäßig strlen () als länger interpretiert werden, als sie wirklich sind, da ein einzelnes Zeichen zwei oder mehr Bytes anstelle von nur einem Byte benötigt. Wenn Sie nur die Funktionen strlen ()/substr () verwenden, um Zeichenfolgen zu teilen, können Sie eine Zeichenfolge in der Mitte eines Zeichens teilen! Im Zweifel sind mb_strlen () / mb_substr () etwas narrensicherer.

9

Verwenden Sie 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;

Dadurch erhalten Sie eine Zeichenfolge, die nach 30 Zeichen an der ersten Stelle abgeschnitten wird.

8
Lucas Oman

Hier ist meine Funktion, die auf dem Ansatz von @ Cd-MaN basiert.

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

  return $string;
}
5
Camsoft

Bitte schön:

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

Es ist überraschend, wie schwierig es ist, die perfekte Lösung für dieses Problem zu finden. Ich habe auf dieser Seite noch keine Antwort gefunden, die zumindest in einigen Situationen nicht fehlschlägt (insbesondere wenn die Zeichenfolge Zeilenumbrüche oder Tabulatoren enthält oder wenn der Wortumbruch etwas anderes als ein Leerzeichen ist oder wenn die Zeichenfolge UTF-Zeichen enthält.) 8 Multibyte-Zeichen).

Hier ist eine einfache Lösung, die in allen Fällen funktioniert. Hier gab es ähnliche Antworten, aber der Modifikator "s" ist wichtig, wenn er mit mehrzeiliger Eingabe arbeiten soll. Mit dem Modifikator "u" werden UTF-8-Multibyte-Zeichen korrekt ausgewertet.

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

Ein möglicher Edge-Fall in diesem Fall ... Wenn die Zeichenfolge in den ersten $ characterCount-Zeichen überhaupt keine Leerzeichen enthält, wird die gesamte Zeichenfolge zurückgegeben. Wenn Sie es vorziehen, bei $ characterCount einen Umbruch zu erzwingen, auch wenn es sich nicht um eine Word-Grenze handelt, können Sie Folgendes 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 Ellipsen hinzugefügt werden sollen, wenn die Zeichenfolge abgeschnitten wird ... 

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

Beschreibung:

  • ^ - Beginne am Anfang der Zeichenkette
  • ([\s\S]{1,200}) - Liefert 1 bis 200 Zeichen
  • [\s]+? - Leerzeichen am Ende des Kurztextes nicht einschließen, sodass Word ... anstelle von Word...
  • [\s\S]+ - passt zu allen anderen Inhalten

Tests:

  1. regex101.com lassen Sie uns noch einige andere or zu r hinzufügen
  2. regex101.comorrrr genau 200 Zeichen.
  3. regex101.com nach fünfter rorrrrr ausgeschlossen.

Genießen.

3
hlcs

Ok, also habe ich eine andere Version davon bekommen, die auf den obigen Antworten basiert, aber mehr Dinge berücksichtigt (utf-8,\n und & nbsp;).

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

Verwendungszweck:

$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 gibt die ersten 10 Wörter aus.

Die preg_split-Funktion wird verwendet, um eine Zeichenfolge in Teilzeichenfolgen aufzuteilen. Die Grenzen, an denen die Zeichenfolge aufgeteilt werden soll, werden mit einem Muster für reguläre Ausdrücke angegeben.

Die preg_split-Funktion benötigt 4 Parameter, aber für uns sind momentan nur die ersten 3 relevant.

Erster Parameter - Muster Der erste Parameter ist das Muster für reguläre Ausdrücke, entlang dem die Zeichenfolge geteilt werden soll. In unserem Fall möchten wir die Zeichenfolge über Word-Grenzen hinweg aufteilen. Daher verwenden wir eine vordefinierte Zeichenklasse \s, die Leerzeichen wie Leerzeichen, Tabulator, Wagenrücklauf und Zeilenvorschub enthält.

Zweiter Parameter - Eingabezeichenfolge Der zweite Parameter ist die lange Textzeichenfolge, die geteilt werden soll.

Dritter Parameter - Limit Der dritte Parameter gibt die Anzahl der Teilstrings an, die zurückgegeben werden sollen. Wenn Sie den Grenzwert auf n setzen, gibt preg_split ein Array mit n Elementen zurück. Die ersten n-1-Elemente enthalten die Teilzeichenfolgen. Das letzte (n th)-Element enthält den Rest der Zeichenfolge.

2
bodi0

Ich würde dazu die preg_match-Funktion verwenden, da Sie einen ziemlich einfachen Ausdruck wünschen.

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

Der Ausdruck bedeutet "stimmen mit jeder Teilzeichenfolge überein, die am Anfang der Länge 1-200 beginnt und mit einem Leerzeichen endet." Das Ergebnis ist in $ result und die Übereinstimmung in $ match. Das kümmert sich um Ihre ursprüngliche Frage, die spezifisch auf jeden Raum endet. Wenn Sie möchten, dass es mit Zeilenumbrüchen endet, ändern Sie den regulären Ausdruck in:

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

So habe ich es gemacht:

$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

Ich habe eine Funktion, die fast das macht, was Sie wollen. Wenn Sie ein paar Änderungen vornehmen, wird sie genau passen:

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

Basierend auf Reginx von @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

Dies ist ein kleiner Fix für die Antwort von mattmac:

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

Der einzige Unterschied besteht darin, ein Leerzeichen am Ende von $ string hinzuzufügen. Dadurch wird sichergestellt, dass das letzte Wort nicht gemäß dem Kommentar von ReX357 abgeschnitten wird.

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

1
tanc

IF/ELSEIF-Anweisungen zum Code von Dave und AmalMurali hinzugefügt, um Zeichenketten ohne Leerzeichen zu behandeln

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

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

Ich erstelle eine Funktion, die eher substr ähnelt und die Idee von @Dave verwendet.

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 .: Der Schnitt in voller Länge kann weniger als substr sein.

0
evandro777

Ich glaube, dass dies der einfachste Weg ist, dies zu tun:

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

Ich verwende die Sonderzeichen, um den Text zu teilen und auszuschneiden.

0
Namida

Ich habe das schon mal benutzt

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

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;

}

Mit dem Puffer können Sie die Länge der zurückgegebenen Zeichenfolge anpassen.

0
Mat Barnett

Benutze das: 

der folgende Code entfernt ','. Wenn Sie ein anderes Zeichen oder eine andere Zeichenfolge haben, können Sie diese anstelle von ',' verwenden.

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

// wenn Sie einen anderen String-Account haben 

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