it-swarm-id.com

Cara Memotong string PHP ke Word yang paling dekat dengan sejumlah karakter tertentu?

Saya memiliki cuplikan kode yang ditulis dalam PHP yang menarik satu blok teks dari database dan mengirimkannya ke widget di laman web. Blok teks asli dapat berupa artikel yang panjang atau satu atau dua kalimat pendek; tetapi untuk widget ini saya tidak dapat menampilkan lebih dari, katakanlah, 200 karakter. Saya dapat menggunakan substr () untuk memotong teks pada 200 karakter, tetapi hasilnya akan terpotong di tengah kata-kata - yang saya benar-benar inginkan adalah memotong teks pada akhir yang terakhir Kata sebelum 200 karakter.

170
Brian

Dengan menggunakan fungsi wordwrap . Ini membagi teks dalam beberapa baris sehingga lebar maksimum adalah yang Anda tentukan, melanggar batas kata. Setelah pemisahan, Anda cukup mengambil baris pertama:

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

Satu hal yang tidak ditangani oleh oneliner ini adalah kasus ketika teks itu sendiri lebih pendek dari lebar yang diinginkan. Untuk menangani kasus Edge ini, seseorang harus melakukan sesuatu seperti:

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

Solusi di atas memiliki masalah memotong teks sebelum waktunya jika mengandung baris baru sebelum cutpoint yang sebenarnya. Di sini versi yang memecahkan masalah ini:

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

Juga, di sini adalah testclass PHPUnit yang digunakan untuk menguji implementasi:

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:

Karakter UTF8 khusus seperti 'à' tidak ditangani. Tambahkan 'u' di akhir REGEX untuk menanganinya:

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

212
Grey Panther

Ini akan mengembalikan 200 karakter kata pertama:

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

Dan begitulah - metode yang dapat diandalkan untuk memotong string ke seluruh Word terdekat, sambil tetap di bawah panjang string maksimum.

Saya sudah mencoba contoh-contoh lain di atas dan mereka tidak menghasilkan hasil yang diinginkan.

42
Dave

Solusi berikut ini lahir ketika saya perhatikan parameter $ break dari wordwrap function:

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

Inilah solusinya:

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

Contoh 1.

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

Contoh di atas akan menampilkan:

This is very long string...

Contoh # 2.

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

Contoh di atas akan menampilkan:

This is short string.
33
Sergiy Sokolenko

Ingatlah setiap kali Anda memisahkan dengan "Word" di mana saja bahwa beberapa bahasa seperti Cina dan Jepang tidak menggunakan karakter spasi untuk memisahkan kata. Selain itu, pengguna jahat dapat dengan mudah memasukkan teks tanpa spasi, atau menggunakan beberapa Unicode yang mirip dengan karakter spasi standar, dalam hal ini solusi apa pun yang Anda gunakan dapat tetap menampilkan seluruh teks. Cara untuk mengatasi hal ini adalah dengan memeriksa panjang string setelah membelahnya pada spasi seperti biasa, kemudian, jika string masih di atas batas abnormal - mungkin 225 karakter dalam kasus ini - terus maju dan membaginya dengan bodoh pada batas itu.

Satu lagi peringatan dengan hal-hal seperti ini ketika datang ke karakter non-ASCII; string yang mengandungnya dapat diinterpretasikan oleh strlen () standar PHP sebagai lebih panjang dari yang sebenarnya, karena satu karakter dapat mengambil dua atau lebih byte daripada hanya satu. Jika Anda hanya menggunakan fungsi strlen ()/substr () untuk membagi string, Anda dapat membagi string di tengah karakter! Jika ragu, mb_strlen () / mb_substr () sedikit lebih mudah.

9
Garrett Albright

Gunakan strpos dan 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;

Ini akan memberi Anda string yang terpotong di ruang pertama setelah 30 karakter.

8
Lucas Oman

Inilah fungsi saya berdasarkan pendekatan @ 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

Ini dia:

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

Mengejutkan betapa sulitnya menemukan solusi sempurna untuk masalah ini. Saya belum menemukan jawaban pada halaman ini yang tidak gagal dalam setidaknya beberapa situasi (terutama jika string berisi baris baru atau tab, atau jika Word break bukan spasi, atau jika string memiliki UTF- 8 karakter multibyte).

Berikut adalah solusi sederhana yang berfungsi dalam semua kasus. Ada jawaban yang serupa di sini, tetapi pengubah "s" penting jika Anda ingin bekerja dengan input multi-line, dan pengubah "u" membuatnya mengevaluasi dengan benar karakter multiby UTF-8.

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

Satu kemungkinan Edge case dengan ini ... jika string tidak memiliki spasi sama sekali dalam $ characterCount karakter pertama, itu akan mengembalikan seluruh string. Jika Anda menginginkannya memaksa break pada $ characterCount bahkan jika itu bukan batas Word, Anda dapat menggunakan ini:

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

Satu opsi terakhir, jika Anda ingin menambahkan Ellipsis jika memotong string ... 

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

Deskripsi:

  • ^ - mulai dari awal string
  • ([\s\S]{1,200}) - dapatkan dari 1 hingga 200 karakter apa pun
  • [\s]+? - tidak termasuk spasi di akhir teks pendek sehingga kita dapat menghindari Word ... alih-alih Word...
  • [\s\S]+ - cocok dengan semua konten lainnya

Tes:

  1. regex101.com mari kita tambahkan ke or beberapa r lainnya
  2. regex101.comorrrr tepatnya 200 karakter.
  3. regex101.com setelah kelima rorrrrr dikecualikan.

Nikmati.

3
hlcs

Ok jadi saya mendapatkan versi lain dari ini berdasarkan jawaban di atas tetapi mengambil lebih banyak hal dalam akun (utf-8,\n dan & nbsp;), juga baris yang menghapus kode pendek wordpress yang dikomentari jika digunakan dengan 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);
}

Pemakaian:

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

Ini akan menghasilkan 10 kata pertama.

Fungsi preg_split digunakan untuk membagi string menjadi substring. Batas-batas di mana string harus dipisah, ditentukan menggunakan pola ekspresi reguler.

Fungsi preg_split mengambil 4 parameter, tetapi hanya 3 yang pertama yang relevan bagi kami saat ini.

Parameter Pertama - Pola Parameter pertama adalah pola ekspresi reguler di mana string harus dipisah. Dalam kasus kami, kami ingin membagi string melintasi batas-batas Word. Oleh karena itu kami menggunakan kelas karakter yang telah ditentukan \s yang cocok dengan karakter spasi putih seperti spasi, tab, carriage return, dan umpan baris.

Parameter Kedua - Input String Parameter kedua adalah string teks panjang yang ingin kita bagi.

Parameter Ketiga - Batas Parameter ketiga menentukan jumlah substring yang harus dikembalikan. Jika Anda menetapkan batas ke n, preg_split akan mengembalikan array n elemen. Elemen n-1 pertama akan berisi substring. Elemen (n th) terakhir akan berisi sisa dari string.

2
bodi0

Saya akan menggunakan fungsi preg_match untuk melakukan ini, karena apa yang Anda inginkan adalah ekspresi yang cukup sederhana.

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

Ekspresi berarti "cocok dengan setiap substring mulai dari awal panjang 1-200 yang berakhir dengan spasi." Hasilnya dalam $ hasil, dan pertandingan dalam $ cocok. Itu menangani pertanyaan awal Anda, yang secara khusus berakhir pada ruang apa pun. Jika Anda ingin mengakhiri di baris baru, ubah ekspresi reguler menjadi:

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

Beginilah cara saya melakukannya:

$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

Saya memiliki fungsi yang melakukan hampir apa yang Anda inginkan, jika Anda akan melakukan beberapa pengeditan, itu akan pas:

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

Berdasarkan regex @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

Ini adalah perbaikan kecil untuk jawaban mattmac:

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

Satu-satunya perbedaan adalah menambahkan spasi di akhir $ string. Ini memastikan Firman terakhir tidak terpotong sesuai komentar ReX357.

Saya tidak memiliki cukup poin rep untuk menambahkan ini sebagai komentar.

1
tanc

Menambahkan pernyataan IF/ELSEIF ke kode dari Dave dan AmalMurali untuk menangani string tanpa spasi

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

Saya tahu ini sudah tua, tapi ...

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

Saya membuat fungsi yang lebih mirip dengan substr, dan menggunakan ide @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 .: Pemotongan panjang penuh mungkin kurang dari substr.

0
evandro777

Saya percaya ini adalah cara termudah untuk melakukannya:

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

Saya menggunakan karakter khusus untuk membagi teks dan memotongnya.

0
Namida

Saya menggunakan ini sebelumnya

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

Saya menemukan ini berfungsi:

function singkatanate_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;

}

Buffer memungkinkan Anda untuk menyesuaikan panjang string yang dikembalikan.

0
Mat Barnett

Gunakan ini: 

kode berikut akan menghapus ','. Jika Anda memiliki karakter atau sub-string lain, Anda dapat menggunakannya sebagai ganti ','

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

// jika Anda memiliki akun string lain untuk 

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