web-dev-qa-db-ja.com

PHPの文字列を特定の文字数に最も近いWordに切り捨てる方法は?

PHPで記述されたコードスニペットを使用して、データベースからテキストブロックを取得し、それをWebページ上のウィジェットに送信します。テキストの元のブロックは、長い記事でも短い文章でも2つでもかまいません。しかし、このウィジェットでは、たとえば200文字までしか表示できません。 substr()を使用して200文字でテキストを切り取ることができますが、結果は単語の途中で途切れることになります。  200文字の前。

173
Brian

wordwrap 関数を使用します。最大幅が指定した幅になるようにテキストを複数行に分割し、Wordの境界で分割します。分割後、最初の行を取得するだけです:

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

このonelinerが処理しないことの1つは、テキスト自体が目的の幅より短い場合です。このエッジケースを処理するには、次のようにする必要があります。

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

上記のソリューションには、実際のカットポイントの前に改行が含まれている場合、テキストを途中でカットするという問題があります。この問題を解決するバージョンは次のとおりです。

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

また、実装のテストに使用されるPHPUnitテストクラスは次のとおりです。

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

編集:

「à」などの特殊なUTF8文字は処理されません。 REGEXの最後に「u」を追加して処理します。

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

214
Grey Panther

これは、単語の最初の200文字を返します。

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

そして、そこにあなたはそれを持っている-最大の文字列の長さの下に留まりながら、最も近いWord全体に任意の文字列を切り捨てる信頼性の高い方法。

上記の他の例を試しましたが、期待した結果が得られませんでした。

43
Dave

wordwrap 関数の$ breakパラメーターに気付いたときに、次の解決策が生まれました。

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

ここにがあります:

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

例#1。

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

上記の例は次を出力します:

This is very long string...

例#2。

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

上記の例は次を出力します:

This is short string.
34

中国語や日本語などの一部の言語では単語を分割するためにスペース文字を使用していない場合、「単語」で分割する場合は常に注意してください。また、悪意のあるユーザーは単にスペースなしでテキストを入力するか、標準のスペース文字に似たUnicodeを使用することができます。その場合、使用するソリューションはいずれにしてもテキスト全体を表示する可能性があります。これを回避する方法は、通常のようにスペースで文字列を分割した後、文字列の長さをチェックすることです。その後、文字列がまだ異常な制限(この場合は225文字)を超えている場合、先に進み、その制限でそれを無理に分割します。

ASCII以外の文字に関しては、このようなことに関するもう1つの注意点があります。それらを含む文字列は、PHPの標準strlen()によって実際よりも長いと解釈される場合があります。これは、1文字が1バイトではなく2バイト以上かかる場合があるためです。 strlen()/ substr()関数を使用して文字列を分割するだけの場合、文字の途中で文字列を分割できます!疑わしい場合は、- mb_strlen() / mb_substr() がもう少し確実です。

9

Strposと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;

これにより、30文字の後の最初のスペースで切り捨てられた文字列が得られます。

8
Lucas Oman

@ 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

どうぞ:

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

この問題の完璧な解決策を見つけるのがどれほど難しいかは驚くべきことです。このページで、少なくともいくつかの状況で失敗しない答えはまだ見つかりません(特に、文字列に改行またはタブが含まれている場合、Wordの区切りがスペース以外の場合、または文字列にUTF- 8マルチバイト文字)。

すべての場合に機能する簡単なソリューションを次に示します。ここにも同様の回答がありましたが、「s」修飾子は複数行入力で機能する場合に重要であり、「u」修飾子はUTF-8マルチバイト文字を正しく評価します。

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

これに関する可能性のあるEdgeのケース...最初の$ characterCount文字に文字列に空白がまったく含まれていない場合、文字列全体が返されます。 Wordの境界でなくても、強制的に$ characterCountでブレークする場合は、これを使用できます。

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

最後のオプションとして、文字列を切り捨てる場合に省略記号を追加する場合...

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

説明:

  • ^-文字列の先頭から開始
  • ([\s\S]{1,200})-1から200までの任意の文字を取得
  • [\s]+?-短いテキストの最後にスペースを含めないで、Word ...の代わりにWord...を避けることができます
  • [\s\S]+-他のすべてのコンテンツと一致

テスト:

  1. regex101.comorにいくつか追加してみましょうr
  2. regex101.comorrrr正確に200文字。
  3. regex101.com 5番目の後rorrrrr除外。

楽しい。

3
hlcs

わかりましたので、上記の回答に基づいて別のバージョンを取得しましたが、アカウント(utf-8、\ nおよび&nbsp;)でより多くのものを取り、wpで使用した場合はwordpressショートコードを削除する行もコメントしました.

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

使用法:

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

これにより、最初の10ワードが出力されます。

preg_split関数は、文字列を部分文字列に分割するために使用されます。文字列を分割する境界は、正規表現パターンを使用して指定されます。

preg_split関数は4つのパラメーターを取りますが、現在は最初の3つだけが関連しています。

最初のパラメーター-パターン最初のパラメーターは、文字列を分割する正規表現パターンです。この例では、文字列をWordの境界を越えて分割します。したがって、スペース、タブ、キャリッジリターン、ラインフィードなどの空白文字に一致する定義済みの文字クラス\sを使用します。

2番目のパラメーター-入力文字列2番目のパラメーターは、分割する長いテキスト文字列です。

3番目のパラメーター-制限3番目のパラメーターは、返されるサブストリングの数を指定します。制限をnに設定すると、preg_splitはn要素の配列を返します。最初のn-1要素にはサブストリングが含まれます。最後の(n th)要素には、残りの文字列が含まれます。

2
bodi0

必要なのは非常に単純な式なので、これを行うにはpreg_match関数を使用します。

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

この表現は、「長さが1〜200で始まり、スペースで終わる部分文字列に一致する」ことを意味します。結果は$ resultにあり、一致は$ matchesにあります。これで元の質問が処理されます。これは、具体的には任意のスペースで終了します。改行で終わらせたい場合は、正規表現を次のように変更します。

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

これは私がそれをやった方法です:

$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

私はあなたが望むもののほとんどを実行する機能を持っています、あなたがいくつかの編集を行うならば、それは正確にフィットします:

<?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の正規表現に基づく:

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

これは、mattmacの答えの小さな修正です。

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

唯一の違いは、$ stringの末尾にスペースを追加することです。これにより、ReX357のコメントに従って最後のWordが切り捨てられないことが保証されます。

これをコメントとして追加するのに十分な担当者がいません。

1
tanc

スペースなしの文字列を処理するための Dave および AmalMurali のコードにIF/ELSEIFステートメントを追加しました

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

私はこれが古いことを知っていますが...

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

Substrに似た関数を作成し、@ 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);
}

追伸:全長カットはsubstrより短い場合があります。

0
evandro777

これが最も簡単な方法だと思います:

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

テキストを分割して切り取るために特殊文字を使用しています。

0
Namida

前にこれを使った

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

私はこれがうまくいくと思う:

関数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;

}

バッファを使用すると、返される文字列の長さを調整できます。

0
Mat Barnett

これを使って:

次のコードは「、」を削除します。他の文字またはサブストリングがある場合は、「、」の代わりにそれを使用できます

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

//別の文字列アカウントがある場合

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