it-swarm-tr.com

Bir dize kesmek nasıl PHP belirli sayıda karaktere en yakın Word'e?

PHP 'de yazılan ve kod bloğunu bir veritabanından alan ve bir web sayfasındaki bir widget'a gönderen bir kod pasajı var. Orijinal metin bloğu uzun bir makale veya kısa bir cümle olabilir; ama bu widget için 200 karakterden daha fazlasını gösteremiyorum. Substr () kullanarak metni 200 karakterde kesmek için kullanabilirim, ancak sonuç kelimelerin ortasında kesiliyordu - gerçekten istediğim metni sonunda kesmek. Sözcük 200 karakterden önce.

170
Brian

wordwrap işlevini kullanarak. Metinleri birden fazla satırda böler, böylece maksimum genişlik sizin belirttiğiniz, Word sınırlarını kırar. Bölme işleminden sonra ilk satırı seçmeniz yeterlidir:

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

Bu oneliner'ın işlemediği bir şey, metnin kendisinin istenen genişlikten daha kısa olduğu durumdur. Bu Edge davasını ele almak için kişi şöyle bir şey yapmalı:

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

Yukarıdaki çözüm, gerçek kesim noktasından önce yeni bir satır içeriyorsa, metnin erken kesilmesi problemine sahiptir. İşte bu sorunu çözen bir sürüm:

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

Ayrıca, uygulamayı test etmek için kullanılan PHPUnit test sınıfı:

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

DÜZENLE :

'À' gibi özel UTF8 karakterleri işlenmez. İşlemek için REGEX'in sonuna 'u' ekleyin:

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

212
Grey Panther

Bu, kelimelerin ilk 200 karakterini döndürür:

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

Ve işte orada - maksimum dize uzunluğunun altında kalırken, herhangi bir dizgiyi en yakın bütün Word'e kesmek için güvenilir bir yöntem.

Yukarıdaki diğer örnekleri denedim ve bunlar istenen sonuçları vermedi.

42
Dave

Aşağıdaki çözüm, wordwrap function $ break parametresini gördüğümde ortaya çıktı:

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

İşte çözüm:

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

Örnek 1.

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

Yukarıdaki örnek çıktı verecektir:

This is very long string...

Örnek 2.

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

Yukarıdaki örnek çıktı verecektir:

This is short string.
33
Sergiy Sokolenko

Çince ve Japonca gibi bazı dillerin kelimeleri bölmek için boşluk karakteri kullanmadığı herhangi bir yerde "Word" e böldüğünüzde aklınızda bulundurun. Ayrıca, kötü niyetli bir kullanıcı herhangi bir boşluk bırakmadan veya standart boşluk karakterine benzer bazı Unicode görünümleri kullanarak metin girebilir; bu durumda kullandığınız herhangi bir çözüm, metnin tamamının görüntülenmesine neden olabilir. Bunun etrafındaki bir yol, dize uzunluğunu normal olarak boşluklara böldükten sonra kontrol etmek olabilir, o zaman, dize hala anormal bir sınırın üzerindeyse - bu durumda belki 225 karakter - devam ediyor ve bu sınırda aptalca bölmek.

ASCII olmayan karakterlere gelince, bunun gibi şeylerle ilgili bir uyarı daha; Bunları içeren dizeler PHP'nin standart strlen () 'in gerçekte olduğundan daha uzun olduğu şeklinde yorumlanabilir, çünkü tek bir karakter sadece bir tane yerine iki veya daha fazla byte alabilir. Dizeleri bölmek için sadece strlen ()/substr () işlevlerini kullanırsanız, karakterin ortasında bir dize bölebilirsiniz! Şüphe duyduğunuzda, mb_strlen () / mb_substr () , biraz daha kusursuzdur.

9
Garrett Albright

Strpos ve substr kullanın:

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

Bu, 30 karakterden sonra ilk alanda kesilen bir dize verecektir.

8
Lucas Oman

İşte @ Cd-MaN'ın yaklaşımını temel alan fonksiyonum.

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

  return $string;
}
5
Camsoft

Hadi bakalım:

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

Bu soruna en iyi çözümü bulmanın ne kadar zor olduğu şaşırtıcı. Bu sayfada, en azından bazı durumlarda başarısız olmayan bir cevap bulamadım (özellikle dize yeni satırlar veya sekmeler içeriyorsa veya Word sonu bir boşluktan başka bir şeyse veya dizede UTF varsa) 8 çok baytlık karakter).

İşte her durumda işe yarayan basit bir çözüm. Burada benzer cevaplar vardı, ancak "s" değiştiricisi çok satırlı girişle çalışmasını istiyorsanız önemlidir ve "u" değiştiricisi UTF-8 çok baytlı karakterleri doğru şekilde değerlendirmesini sağlar.

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

Bunun olası bir Edge durumu ... eğer dizge ilk $ characterCount karakterlerinde hiç boşluk bırakmazsa, dizgenin tamamını döndürür. Eğer Word sınırı olmasa bile $ characterCount'ta bir mola vermeye zorlarsanız, şunu kullanabilirsiniz:

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

Son bir seçenek, dizgiyi keserse, Ellipsis ekletmek isterseniz ... 

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

Açıklama:

  • ^ - dizenin başından başla
  • ([\s\S]{1,200}) - Herhangi bir karakterden 1 ile 200 arası
  • [\s]+? - kısa metnin sonuna boşluk içermez, böylece Word ... yerine Word...'dan kaçınabiliriz
  • [\s\S]+ - diğer tüm içeriği eşleştir

Testler:

  1. regex101.com / __ or 'a ekleyelim birkaç tane r
  2. regex101.comorrrr tam 200 karakter.
  3. regex101.com / beşte sonra rorrrrr hariç.

Keyfini çıkarın.

3
hlcs

Tamam, yukarıdaki cevaplara dayanarak bunun başka bir versiyonunu aldım, ancak daha fazla şeyi dikkate alarak (utf-8,\n ve & nbsp;), ayrıca wp ile kullanılırsa yorumlanan wordpress kısa kodlarını soyan bir satır aldım.

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

Kullanımı:

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

Bu ilk 10 kelimeyi çıkartacaktır.

preg_split işlevi bir dizgiyi alt dizgelere bölmek için kullanılır. Dizenin bölüneceği sınırlar, normal ifadeler deseni kullanılarak belirlenir.

preg_split işlevi 4 parametre alır, ancak şu anda yalnızca ilk 3 tanesi bizimle ilgilidir.

First Parameter - Pattern İlk parametre, dizgenin bölüneceği düzenli ifadelerdir. Bizim durumumuzda, dizgiyi Word sınırları boyunca bölmek istiyoruz. Bu nedenle, boşluk, sekme, satır başı ve satır besleme gibi beyaz boşluk karakterleriyle eşleşen önceden tanımlanmış bir karakter sınıfı \s kullanıyoruz.

İkinci Parametre - Giriş Dizesi İkinci parametre bölmek istediğimiz uzun metin dizesidir.

Üçüncü Parametre - Limit .__ Üçüncü parametre, döndürülmesi gereken alt dizelerin sayısını belirtir. Sınırı n olarak ayarlarsanız, preg_split bir n öğesi dizisi döndürür. İlk n-1 elemanları alt dizileri içerecektir. Son (n th) öğesi, dizenin geri kalanını içerecektir.

2
bodi0

Bunu yapmak için preg_match işlevini kullanırdım, çünkü istediğiniz şey oldukça basit bir ifadedir.

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

İfade, "1-200 uzunluğunun başından başlayarak boşlukla biten herhangi bir alt dizeyle eşleşir" anlamına gelir. Sonuç $ sonucunda ve maç $ maçlarında. Bu, özellikle herhangi bir alanda sona eren özgün sorunuzla ilgilenir. Bunu yeni satırlarda sonlandırmak istiyorsanız normal ifadeyi şu şekilde değiştirin:

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

Bu nasıl yaptım:

$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

Neredeyse istediğini yapan bir işleve sahibim, eğer birkaç düzenleme yapacaksan, tam olarak uyuyor:

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

@Justin Poliey'nin regex'i temel alınmıştır:

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

Bu mattmac'ın cevabı için küçük bir düzeltme:

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

Tek fark, $ string'in sonuna boşluk eklemek. Bu, son Word'ün ReX357'nin yorumuna göre kesilmemesini sağlar.

Bunu yorum olarak eklemek için yeterli puanım yok.

1
tanc

Boşluksuz dizeleri işlemek için Dave ve AmalMurali koduna IF/ELSEIF deyimleri eklendi.

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

Bunun eski olduğunu biliyorum ama ...

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

Substr'a daha çok benzeyen ve @Dave fikrini kullanarak bir fonksiyon yaratıyorum.

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 .: Tam boy kesim substr'den daha az olabilir.

0
evandro777

Bunu yapmanın en kolay yolu olduğuna inanıyorum:

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

Metni bölmek ve kesmek için özel karakterler kullanıyorum.

0
Namida

Bunu daha önce kullandım

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

Bu işleri buluyorum:

işlevi 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;

}

Arabellek, döndürülen dizenin uzunluğunu ayarlamanıza izin verir.

0
Mat Barnett

Bunu kullan: 

aşağıdaki kod ',' kaldıracak. Başka bir karakteriniz veya alt dizginiz varsa, bunu ',' yerine kullanabilirsiniz

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

// için başka bir dize hesabınız varsa 

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