У меня есть длинный текст, как показано ниже:
$postText="It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.";
Я хочу добавить гиперссылку readmore после 170 символов без обрезания слова и включения завершающего пробела.
Моя попытка кодирования:
if(strlen($postText)>170){
$splitArr=preg_split("/.{170}\S*\s/",$postText,2);
print_r($splitArr);
exit;
$postText=$splitArr[0]."...<a class='see-more' href='http://example.com/seemore-link'>read more</a>";
}
Разделенный массив всегда возвращает первый индекс как null
, Я проверил свое регулярное выражение в REGEX101, и это показывает именно то, что мне нужно. Пожалуйста, укажите, что не так.
Массив split всегда возвращает первый индекс как ноль.
Не возвращается NULL
, он возвращает пустое строка (''
); это совершенно разные объекты с разной семантикой.
Причина, по которой первый элемент возвращаемого массива является пустой строкой, четко задокументирована на странице руководства preg_split()
:
Возвращаемые значения:
Возвращает массив, содержащий подстроки
subject
разделить вдоль границ, соответствующихpattern
, или жеFALSE
на провал.
Регулярное выражение, которое вы предоставляете в качестве первого аргумента preg_split()
используется для соответствия разделителю, а не частям. Функция, которая вам нужна preg_match()
:
$postText = "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.";
preg_match('/^.{170}\S*/', $postText, $matches);
$postText = $matches[0] . " ...<a class='see-more' href='http://example.com/seemore-link'>read more</a>";
Если preg_match()
возвращается TRUE
, $matches[0]
содержит строку, которая вам нужна
Есть ситуации, когда preg_match()
не удается с вашим оригиналом regex
, Например, если ваша входная строка содержит ровно 170 символов, \s
не будет соответствовать Вот почему я удалил \s
от regex
и добавил пробел перед строкой, добавленной после матча.
Почему preg_split()
возвращать пустую строку для первого элемента?
Это потому, что шаблон, который вы используете для функции, определяет, где она должна взорваться / сломаться. Совпадающие символы обрабатываются как «разделитель» и фактически удаляются с использованием поведения функции по умолчанию.
Когда ваша входная строка содержит не менее 170 символов, затем необязательные непробельные символы, затем пробельные символы — все эти совпадающие символы становятся разделителями. когда preg_split()
разбивает строку, потенциально генерирует элементы нулевой длины в зависимости от расположения разделителя.
Например, если у вас есть строка aa
и разделить его на a
, функция вернет 3 пустых элемента — один перед первым a
, один между a
и один за вторым a
,
Код: (демонстрация)
$string = "aa";
var_export(preg_split('/a/', $string));
// output: array ( 0 => '', 1 => '', 2 => '', )
Чтобы гарантировать, что пустые строки не генерируются, вы можете установить четвертый параметр функции в PREG_SPLIT_NO_EMPTY
(3-й параметр должен быть объявлен для того, чтобы 4-й параметр был распознан).
var_export(preg_split('/a/', $string, -1, PREG_SPLIT_NO_EMPTY));
// output: array ( )
Вы мог добавить PREG_SPLIT_NO_EMPTY
параметр вашего вызова функции, чтобы удалить пустую строку, но поскольку подстрока, которую вы хотите сохранить, используется в качестве разделителя, она теряется в процессе.
Более важным вопросом является тот факт, что preg_split()
не лучший инструмент для этой работы.
Ваш опубликованный фрагмент:
$postText
с элементом, содержащим начальную часть и конкатенирует гиперссылку с многоточием.Код: (демонстрация)
$postText = "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.";
$ellipsis = "...<a class='see-more' href='http://example.com/seemore-link'>read more</a>";
echo preg_replace('/.{170}\S*\s\K.+/', $ellipsis, $postText);
Прелесть этого звонка в том, что если $postText
не подходит для усечения, потому что в нем нет 170 символов, за которыми могут следовать непробельные символы, затем символ пробела, тогда ничего не происходит — строка остается целой.
\K
в шаблонах команд, что первые ~ 170 символов освобожден / забыли / выброшенного как подобранные персонажи. Тогда .+
средства соответствовать одному или нескольким персонажам (насколько это возможно). По этой логике шаблона будет выполняться только одна замена. preg_replace()
модифицирует $postText
строка без какого-либо синтаксиса конкатенации.
* обратите внимание, если ваша строка ввода может содержать символы новой строки, вы должны добавить s
модификатор картины, так что .
будет соответствовать любой символ, включая символы новой строки. Шаблон: /.{170}\S*\s\K.+/s
* если вы хотите обрезать входную строку в конце слова после 170-го символа, вы можете использовать этот шаблон: /.{170}\S*\K.+/
и вы можете добавить пробел в начале строки замены / многоточия, чтобы обеспечить некоторое разделение.
Использование подхода без регулярных выражений немного более неуклюже и требует условного выражения для поддержания того же уровня точности (поэтому я не рекомендую его, но я все равно покажу технику).
С помощью substr_replace()
необходимо проверить, достаточно ли длины в строке, чтобы предложить правильное смещение для strpos()
, Если это так, вы можете заменить.
Код: (демонстрация)
$postText = "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.";
$ellipsis = "...<a class='see-more' href='http://example.com/seemore-link'>read more</a>";
if (($len = strlen($postText)) > 170 && ($pos = strpos($postText, ' ', 170)) && ++$pos < $len){
$postText = substr_replace($postText, $ellipsis, $pos);
}
echo $postText;
В приведенном выше фрагменте предполагается, что во входной строке есть только пробелы (по сравнению с символами табуляции и символами новой строки, которые вы можете разделить).
Ваше регулярное выражение .{170}\S*\s
это хорошо, но есть небольшая проблема. Это не гарантирует, если \S*
соответствует остатку слова, так как он может соответствовать значению MD5 — 170 до первого символа хеша MD5, а затем соответствует еще 31 символу, который может быть больше этого.
Вы рассматриваете эти 170 символов как разделитель preg_split
следовательно, у вас не было его на выходе.
Принимая во внимание эти две вещи, вы можете прийти с лучшей идеей:
$array = preg_split('~^[\s\S]{1,170}+(?(?!\S{10,})\S*)\K~', $string);
10
обеспечивает отсутствие непробельных символов, кроме этого. Если существует, он разделяется сразу после 170 символов.
Доступ к $array[0]
Вы можете добавить свой текст для чтения к нему.
Там нет необходимости использовать preg_split вы все еще можете обрезать символы с зиЬзЬг.
$postText="It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy.";
$limit = 170;
$truncated = substr($postText,0,$limit);
$truncated .= "...<a class='see-more' href='http://example.com/seemore-link'>read more</a>";
var_dump($truncated);