دمج تعبيرين منتظمين لاقتطاع الكلمات في الأوتار
سؤال
أحاول التوصل إلى الوظيفة التالية التي تقطع السلسلة إلى كلمات كاملة (إن أمكن ، وإلا يجب أن تقطع إلى chars):
function Text_Truncate($string, $limit, $more = '...')
{
$string = trim(html_entity_decode($string, ENT_QUOTES, 'UTF-8'));
if (strlen(utf8_decode($string)) > $limit)
{
$string = preg_replace('~^(.{1,' . intval($limit) . '})(?:\s.*|$)~su', '$1', $string);
if (strlen(utf8_decode($string)) > $limit)
{
$string = preg_replace('~^(.{' . intval($limit) . '}).*~su', '$1', $string);
}
$string .= $more;
}
return trim(htmlentities($string, ENT_QUOTES, 'UTF-8', true));
}
فيما يلي بعض الاختبارات:
// Iñtërnâtiônàlizætiøn and then the quick brown fox... (49 + 3 chars)
echo dyd_Text_Truncate('Iñtërnâtiônàlizætiøn and then the quick brown fox jumped overly the lazy dog and one day the lazy dog humped the poor fox down until she died.', 50, '...');
// Iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_... (50 + 3 chars)
echo dyd_Text_Truncate('Iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_jumped_overly_the_lazy_dog and one day the lazy dog humped the poor fox down until she died.', 50, '...');
كلاهما يعملان كما هو ، ولكن إذا أسقطت الثانية preg_replace()
أحصل على ما يلي:
iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_jumped_overly_the_lazy_dog وفي يوم من الأيام ، قام الكلب الكسول بحماس الثعلب الفقير إلى أسفل حتى ماتت ....
لا يمكنني استخدام substr()
لأنه يعمل فقط على مستوى البايت وليس لدي إمكانية الوصول إليه mb_substr()
ATM ، لقد بذلت عدة محاولات للانضمام إلى Regex الثاني مع أول واحد ولكن دون نجاح.
الرجاء مساعدة الرسائل القصيرة ، لقد كنت أعاني من هذا لمدة ساعة تقريبًا.
تحرير: أنا آسف ، لقد كنت مستيقظًا لمدة 40 ساعة وفقدت هذا دون خجل:
$string = preg_replace('~^(.{1,' . intval($limit) . '})(?:\s.*|$)?~su', '$1', $string);
ومع ذلك ، إذا كان لدى شخص ما regex أكثر تحسنا (أو واحد يتجاهل المساحة الخلفية) يرجى المشاركة:
"Iñtërnâtiônàlizætiøn and then "
"Iñtërnâtiônàlizætiøn_and_then_"
تحرير 2: ما زلت لا أستطيع التخلص من المسافة البيضاء الزائدة ، هل يمكن لأحد أن يساعدني؟
تحرير 3: حسنًا ، لم ينجح أي من تعديلاتاتي حقًا ، لقد كنت ينخدع بواسطة regexbuddy - ربما يجب أن أترك هذا ليوم آخر وأحصل على بعض النوم الآن. قبالة لهذا اليوم.
المحلول
ربما يمكنني أن أعطيك صباحًا سعيدًا بعد ليلة طويلة من كوابيس Regexp:
'~^(.{1,' . intval($limit) . '}(?<=\S)(?=\s)|.{'.intval($limit).'}).*~su'
غليه:
^ # Start of String
( # begin capture group 1
.{1,x} # match 1 - x characters
(?<=\S)# lookbehind, match must end with non-whitespace
(?=\s) # lookahead, if the next char is whitespace, match
| # otherwise test this:
.{x} # got to x chars anyway.
) # end cap group
.* # match the rest of the string (since you were using replace)
يمكنك دائما إضافة |$
حتى نهاية (?=\s)
ولكن نظرًا لأن الرمز الخاص بك كان يتحقق بالفعل من أن طول السلسلة كان أطول من $limit
, ، لم أشعر أن هذه القضية ستكون ضارة.
نصائح أخرى
هل فكرت في استخدام WordWrap؟ ((http://us3.php.net/wordwrap)