2010-04-21 8 views
7

Próbuję wymyślić następującej funkcji, która obcina ciąg całych wyrazów (jeśli to możliwe, w przeciwnym razie należy obciąć do znaków):Scalanie dwóch wyrażeń regularnych obciąć słowa Strings

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

Oto Niektóre testy:

// 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, '...'); 

obaj praca jak to jest, jednak, jeśli wpadnę drugi preg_replace() uzyskać następujące:

Iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_jumped_overly_the_lazy_dog i jeden dzień leniwy pies garbaty się słabe lisa, aż zmarła ....

Nie mogę korzystać substr() ponieważ działa tylko na poziomie bajtów i nie mam dostępu do mb_substr() ATM, kilka razy próbowałem dołączyć do drugiego wyrażenia regularnego, ale bez powodzenia.

Proszę pomóżcie S.M.S., zmagałem się z tym przez prawie godzinę.


EDIT: Przepraszam, byłem obudzony przez 40 godzin, a ja bezwstydnie tego brakowało:

$string = preg_replace('~^(.{1,' . intval($limit) . '})(?:\s.*|$)?~su', '$1', $string); 

Mimo to, jeśli ktoś ma bardziej zoptymalizowany regex (lub taki, który ignoruje przestrzeń krocząca) proszę podzielić:

"Iñtërnâtiônàlizætiøn and then " 
"Iñtërnâtiônàlizætiøn_and_then_" 

EDIT 2: I wciąż nie może pozbyć się białych znaków spływu, może ktoś mi pomóc?

EDYCJA 3: W porządku, żadna z moich edycji naprawdę nie działała, zostałem oszukany przez RegexBuddy - prawdopodobnie powinienem zostawić to na inny dzień i przespać się teraz. Off na dziś.

+3

Biedny lis. _____ – kennytm

+0

Dlaczego nie używasz "przycinania", aby pozbyć się spływu białych znaków? – Jens

+3

Obudź się przez 40 godzin i postępuj z regex. +1 litość na głos. –

Odpowiedz

3

Może dam ci szczęśliwego rano po długiej nocy koszmarów RegExp:

'~^(.{1,' . intval($limit) . '}(?<=\S)(?=\s)|.{'.intval($limit).'}).*~su' 

wrzenia go:

^  # 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) 

Zawsze możesz dodać |$ do końca z (?=\s), ale ponieważ twój kod już sprawdzał, czy długość łańcucha jest dłuższa niż $limit, nie sądziłem, że ten przypadek będzie konieczny.

+0

Więcej "szczęśliwego popołudnia", ale dzięki gnarf! Poszedłem spać mając wrażenie, że będę musiał użyć wcześniejszego widoku lub po prostu użyć 'trim()'. Dzięki jeszcze raz! –