Как обрезать целую строку, если она превысит максимальное количество символов? [Дубликат]

Вместо словаря вы также можете использовать namedtuple из модуля коллекций, что облегчает доступ.

например:

#using dictionary
variables = {}
variables["first"] = 34
variables["second"] = 45
print variables["first"], variables["second"]

#using namedtuple
Variables = namedtuple('Variables', ['first', 'second'])
vars = Variables(34, 45)
print vars.first, vars.second
165
задан Brian 17 September 2008 в 05:24
поделиться

25 ответов

Используя функцию wordwrap . Он разбивает тексты на несколько строк таким образом, что максимальная ширина является той, которую вы указали, разбивая границы слов. После расщепления вы просто берете первую строку:

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

. Одна вещь, которую этот oneliner не обрабатывает, - это тот случай, когда текст сам по себе меньше требуемой ширины. Чтобы обработать этот краевой регистр, нужно сделать что-то вроде:

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

EDIT:

Специальные символы UTF8, такие как 'à', не обрабатываются. Добавьте 'u' в конец REGEX для его обработки:

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

208
ответ дан Konrad Kiss 22 August 2018 в 17:53
поделиться
  • 1
    Похоже, что преждевременно отрезать текст, если перед желаемой шириной будет \n. – Kendall Hopkins 19 January 2012 в 02:09
  • 2
    @ KendallHopkins: правда, действительно есть проблема. Я обновил ответ альтернативной реализацией, которая решает данную проблему. – Grey Panther 29 January 2012 в 11:26
  • 3
    Будет ли этот пример работать с строкой, содержащей теги html, как теги абзаца? – Mindthetic 4 July 2012 в 13:38
  • 4
    Это очень крутое решение. Не пользуйтесь им прямо сейчас, но я могу сказать, что не знаю, о чем я знаю. – Foxinni 3 October 2012 в 12:05
  • 5
    Почему бы не добавить: if (strlen ($ string) & lt; = $ your_desired_width) возвращает $ string; как первое утверждение? – Darko Romanov 20 January 2015 в 09:26

Здесь вы можете попробовать

substr( $str, 0, strpos($str, ' ', 200) ); 
-1
ответ дан Abhijeet kumar sharma 22 August 2018 в 17:53
поделиться
  • 1
    Это решение уже упоминалось в других ответах. Проблема с ней в том, что она терпит неудачу, если строка меньше 200 символов, или если она не содержит пробелов. Он также не ограничивает строку длиной до 200 символов, вместо этого она прерывает строку в пространстве после 200 символов, что обычно не является тем, что вы хотите. – orrd 1 September 2015 в 20:04

На основе регулярного выражения @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 22 August 2018 в 17:53
поделиться
/*
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 относятся к нам прямо сейчас.

Первый параметр - шаблон. Первый параметр - это шаблон регулярных выражений, вдоль которого должна быть разбита строка. В нашем случае мы хотим разбить строку на границы слов. Поэтому мы используем предопределенный класс символов \s, который соответствует символам пробела, таким как пробел, вкладка, возврат каретки и фид строки.

Второй параметр - строка ввода Второй параметр - это длинная текстовая строка, которую мы хотим для разделения.

Третий параметр - лимит Третий параметр указывает количество подстрок, которые должны быть возвращены. Если вы установите предел на n, preg_split вернет массив из n элементов. Первые n-1 элементы будут содержать подстроки. Последний элемент (n th) будет содержать остальную часть строки.

2
ответ дан bodi0 22 August 2018 в 17:53
поделиться

Вот моя функция, основанная на подходе @ 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 22 August 2018 в 17:53
поделиться

Добавлены инструкции IF / ELSEIF в код из Dave и AmalMurali для обработки строк без пробелов

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);
}
31
ответ дан Community 22 August 2018 в 17:53
поделиться
  • 1
    это не работает, если строка уже имеет новый символ строки (например, если вы пытаетесь извлечь description сообщения в блоге) – supersan 8 June 2015 в 11:38
  • 2
    @supersan Всегда может выполнять предварительную обработку с помощью preg_replace('/\s+/', ' ', $description), чтобы заменить все пробельные символы одним пробелом;) – Mavelo 11 May 2018 в 17:40
$WidgetText = substr($string, 0, strrpos(substr($string, 0, 200), ' '));

И у вас есть это - надежный метод обрезания любой строки до ближайшего целого слова, оставаясь при максимальной длине строки.

Я пробовал другие примеры выше, и они не дали желаемых результатов.

41
ответ дан Dave 22 August 2018 в 17:53
поделиться
  • 1
    Если длина данной строки меньше максимальной длины, это сократит все до последнего пробела. Чтобы этого избежать, оберните это внутри оператора if: if (strlen($str) > 200) { ... } – Amal Murali 8 May 2014 в 16:36
  • 2
    Простой и, вероятно, намного быстрее, чем другие решения. – Vladan 4 May 2015 в 13:06
  • 3
    Одна из проблем заключается в том, что она возвращает пустую строку, если строка не содержит пробела. – orrd 1 September 2015 в 21:00

Я создаю функцию, более похожую на 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);
}

Ps .: Полное сокращение длины может быть меньше, чем substr.

0
ответ дан evandro777 22 August 2018 в 17:53
поделиться

Имейте в виду, когда вы раскалываетесь «словом» в любом месте, где некоторые языки, такие как китайский и японский, не используют пробельный символ для разделения слов. Кроме того, злоумышленник может просто вводить текст без каких-либо пробелов или использовать какой-либо Юникод похожим на стандартный символ пробела, и в этом случае любое используемое вами решение может в конечном итоге отобразить весь текст. Путь вокруг этого может состоять в том, чтобы проверить длину строки после ее расщепления на пространствах как обычно, тогда, если строка все еще находится над аномальным пределом - может быть, 225 символов в этом случае - вперед и небрежно раскалывает ее в этом пределе.

Еще одно предостережение в таких вещах, когда речь идет о символах, отличных от ASCII; Строки, содержащие их, могут быть интерпретированы стандартным параметром PHP strlen () как длиннее, чем они есть на самом деле, поскольку один символ может принимать два или более байта вместо одного. Если вы просто используете функции strlen () / substr () для разделения строк, вы можете разбить строку в середине символа! Если есть сомнения, mb_strlen () / mb_substr () являются немного более надежными.

9
ответ дан Garrett Albright 22 August 2018 в 17:53
поделиться

Я знаю, что это старый, но ...

function _truncate($str, $limit) {
    if(strlen($str) < $limit)
        return $str;
    $uid = uniqid();
    return array_shift(explode($uid, wordwrap($str, $limit, $uid)));
}
0
ответ дан gosukiwi 22 August 2018 в 17:53
поделиться
$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.com добавим к or несколько других r
  2. regex101.com orrrr ровно 200 символов.
  3. regex101.com после пятого r orrrrr исключено.

Наслаждайтесь .

3
ответ дан hlcs 22 August 2018 в 17:53
поделиться
  • 1
    Я не понимаю документацию по PHP. я знаю, что $1 является «заменой», но в этом конкретном контексте что это значит? пустая переменная? – Anthony 13 April 2018 в 20:15
  • 2
    @Anthony $1 ссылается на совпадение внутри скобок ([\s\S]{1,200}). $2 будет ссылаться на две второй пары скобок, если они есть в шаблоне. – hlcs 14 April 2018 в 09:47
  • 3
    ахх, ладно! благодаря – Anthony 17 April 2018 в 17:49

Я хотел бы использовать функцию preg_match, чтобы сделать это, поскольку то, что вы хотите, является довольно простым выражением.

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

Выражение означает «соответствовать любой подстроке, начиная с начала длины 1-200, что заканчивается пробелом ». Результат получается в $ result, а совпадение - в $ match. Это позаботится о вашем первоначальном вопросе, который определенно заканчивается на любом пространстве. Если вы хотите, чтобы он заканчивался на символах новой строки, измените регулярное выражение на:

$result = preg_match("/^(.{1,199})[\n]/i", $text, $matches);
2
ответ дан Justin Poliey 22 August 2018 в 17:53
поделиться

Вот как я это сделал:

$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
ответ дан Krzysztof Trzos 22 August 2018 в 17:53
поделиться

Использовать 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
ответ дан lajlev 22 August 2018 в 17:53
поделиться
  • 1
    Привет, если длина строки без пробела будет меньше 30, тогда это будет обратная ошибка. и вот результат будет из первых 31 символа, а не 30 .. – Er. Anurag Jain 3 November 2012 в 07:05

Я нахожу, что это работает:

function 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 22 August 2018 в 17:53
поделиться

Это вернет первые 200 символов слов:

preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, 201));
121
ответ дан mattmac 22 August 2018 в 17:53
поделиться
  • 1
    Это действительно работает лучше, чем принятое решение :) – Karan 27 February 2009 в 20:19
  • 2
    Почти. Кажется, что он удаляет последнее слово предложения для меня независимо от того, что. – ReX357 4 August 2011 в 20:19
  • 3
    отлично работает, но я нашел ту же ошибку, что и ReX357. Когда есть более одного слова, он удаляет последний. – Andres SK 26 November 2011 в 18:09
  • 4
    Просто заверните его в чек, чтобы убедиться, что строка длиннее, чем вы тестируете (так же, как и принятый ответ) if (strlen($string) > $your_desired_width) { preg_replace(...); } – Blair McMillan 18 April 2012 в 06:49
  • 5
    Я отредактировал ответ, чтобы включить @BlairMcMillan advice – Kim Stacks 26 March 2014 в 08:46

Я считаю, что это самый простой способ сделать это:

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

Я использую специальные символы, чтобы разделить текст и вырезать его.

0
ответ дан Namida 22 August 2018 в 17:53
поделиться

Удивительно, насколько сложно найти идеальное решение этой проблемы. Я еще не нашел ответа на этой странице, который не сработает, по крайней мере, в некоторых ситуациях (особенно если строка содержит символы новой строки или вкладки, или если слово break является чем-то другим, кроме пробела, или если строка имеет UTF- 8 многобайтовых символов).

Вот простое решение, которое работает во всех случаях. Здесь были похожие ответы, но модификатор «s» важен, если вы хотите, чтобы он работал с многострочным вводом, а модификатор «u» позволяет корректно оценивать многобайтовые символы UTF-8.

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

Один возможный краевой случай с этим ... если строка не имеет пробелов вообще в первых символах $ characterCount, она вернет всю строку. Если вы предпочитаете, чтобы он задерживал разрыв в $ 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 22 August 2018 в 17:53
поделиться

У меня есть функция, которая делает почти то, что вы хотите, если вы сделаете несколько изменений, она будет точно соответствовать:

<?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 22 August 2018 в 17:53
поделиться

Возможно, это поможет кому-то:

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

?>
-2
ответ дан slash3b 22 August 2018 в 17:53
поделиться

Это небольшое исправление для ответа mattmac:

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

Единственное отличие состоит в том, чтобы добавить пробел в конец строки $. Это гарантирует, что последнее слово не будет отрезано в соответствии с комментарием ReX357.

У меня недостаточно точек rep, чтобы добавить это как комментарий.

1
ответ дан tanc 22 August 2018 в 17:53
поделиться

Здесь вы:

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 22 August 2018 в 17:53
поделиться

Хорошо, поэтому я получил еще одну версию этого, основываясь на приведенных выше ответах, но занимая больше вещей в учетной записи (utf-8,\n и & amp; nbsp;), а также строку, разделяющую короткие коды wordpress, прокомментированные, если они используются с 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 22 August 2018 в 17:53
поделиться

Я использовал это до

<?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 22 August 2018 в 17:53
поделиться
[g1] Следующее решение появилось, когда я заметил параметр $ break функции [g0] wordwrap [/g0]: [/g1]
[g2] string wordwrap (string $ str [, int $ width = 75 [, string $ break = "\n" [, bool $ cut = false]]]) [/g2] [g3] Вот решение: [/g3] [f1] [g4] Пример # 1. [/G4] [f2] [g5] Приведенный выше пример выдаст: [/g5] [f3] [g6] Пример # 2. [/G6] [f4] [g7] Приведенный выше пример выдаст: g7] [f5]
32
ответ дан Community 5 November 2018 в 15:22
поделиться
  • 1
    это не работает, если строка уже имеет символ новой строки (например, если вы пытаетесь извлечь getFullYear из сообщения в блоге) – supersan 8 June 2015 в 11:38
  • 2
    @supersan Всегда можно предварительно обработать с помощью
    >>> import pathlib
    >>> fname = pathlib.Path('test.py')
    >>> assert fname.exists(), f'No such file: {fname}'  # check that the file exists
    >>> print(fname.stat())
    os.stat_result(st_mode=33206, st_ino=5066549581564298, st_dev=573948050, st_nlink=1, st_uid=0, st_gid=0, st_size=413, st_atime=1523480272, st_mtime=1539787740, st_ctime=1523480272)
    
    , чтобы заменить все пробельные символы одним пробелом;)
    – Mavelo 11 May 2018 в 17:40
Другие вопросы по тегам:

Похожие вопросы: