0

ギリシャ語で書かれたニュースサイトがあります。

私のホームページでは、各ストーリーのタイトルに加えて、ストーリーのコンテンツのいくつかのキャラクターを表示する必要があります。

設定した文字数制限に合う最後の単語の最後でストーリーの内容をカットしたいと思います。

いくつかのマルチバイトの安全な関数を使用してそれらを組み合わせることでこれを達成しましたが、文字列を切断せずに10ミリ秒未満でロードできるページに約150ミリ秒かかるため、パフォーマンスが非常に高くなるようです。

だから私は疑問に思っています。以下の関数のパフォーマンスを調整し、マルチバイトの安全性を維持する方法はありますか、それともそのまま受け入れる必要がありますか?

// multibyte wordcutter
function cutString( $string , $width = 20 , $cut=false ){
    if( mb_strlen( $string , "UTF-8" ) == 0 ){
        return $string;
        }
    $input = $string;
    if ( mb_strlen( $string , "UTF-8" ) > $width ) {
        $string = mb_wordwrap( $string , $width , "\n" , $cut );
        $string = mb_substr( $string , 0 , mb_strpos( $string , "\n" , NULL , "UTF-8" ) , "UTF-8" );
        if( mb_strlen( $string , "UTF-8" ) > $width ) {
            $string = mb_wordwrap( $string , $width , "\n" , true );
            $string = mb_substr( $string , 0 , mb_strpos( $string , "\n" , NULL , "UTF-8" ) , "UTF-8" );
            }
        elseif( mb_strlen( $string , "UTF-8" ) == 0 ){
            $string = mb_wordwrap( $input , $width , "\n" , true );
            $string = mb_substr( $string , 0 , mb_strpos( $string , "\n" , NULL , "UTF-8" ) , "UTF-8" );
            }
        }
    return $string;
    }

// multibyte safe wordwrap
function mb_wordwrap($string, $width = 75, $break = "\n", $cut = false, $charset = 'utf-8')
{
    $stringWidth = iconv_strlen($string, $charset);
    $breakWidth  = iconv_strlen($break, $charset);

    if (strlen($string) === 0) {
        return '';
    } elseif ($breakWidth === null) {
        throw new Zend_Text_Exception('Break string cannot be empty');
    } elseif ($width === 0 && $cut) {
        throw new Zend_Text_Exception('Can\'t force cut when width is zero');
    }

    $result    = '';
    $lastStart = $lastSpace = 0;

    for ($current = 0; $current < $stringWidth; $current++) {
        $char = mb_substr($string, $current, 1, $charset);

        if ($breakWidth === 1) {
            $possibleBreak = $char;
        } else {
            $possibleBreak = mb_substr($string, $current, $breakWidth, $charset);
        }

        if ($possibleBreak === $break) {
            $result    .= mb_substr($string, $lastStart, $current - $lastStart + $breakWidth, $charset);
            $current   += $breakWidth - 1;
            $lastStart  = $lastSpace = $current + 1;
        } elseif ($char === ' ') {
            if ($current - $lastStart >= $width) {
                $result    .= mb_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
                $lastStart  = $current + 1;
            }

            $lastSpace = $current;
        } elseif ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
            $result    .= mb_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
            $lastStart  = $lastSpace = $current;
        } elseif ($current - $lastStart >= $width && $lastStart < $lastSpace) {
            $result    .= mb_substr($string, $lastStart, $lastSpace - $lastStart, $charset) . $break;
            $lastStart  = $lastSpace = $lastSpace + 1;
        }
    }

    if ($lastStart !== $current) {
        $result .= mb_substr($string, $lastStart, $current - $lastStart, $charset);
    }
    return $result;
}

編集:これは私が使用することになったものです

// multibyte wordcutter
function cutString( $string , $width = 70 , $cut=false ){
    $string = mb_substr( $string , 0 , $width , "UTF-8" );
    if( mb_strlen( $string , "UTF-8" ) < $width ){
        return $string;
        }
    $dot = mb_strripos( $string , '.' , 0 , "UTF-8" ) + 1;
    $space = mb_strripos( $string , ' ' , 0 , "UTF-8" );
    if( $space ){
        if( ($space-$dot) < 20 ){
            $string = mb_substr( $string , 0 , $dot , "UTF-8" );
            }
        else {
            $string = mb_substr( $string , 0 , $space , "UTF-8" );
            }
        }
    return $string;
    }
4

2 に答える 2

1

現在の実装は複雑すぎます。

私が正しく理解していれば、より良い戦略は次のようになります。

  1. 紐を長さでカット
  2. 末尾から最初のスペースまで文字を繰り返します
  3. 中断して結果を返す

これにより、パフォーマンスが大幅に向上するはずです。

于 2012-12-06T09:00:49.957 に答える
1
  1. 実際のテスト ケースと xdebug を使用してパフォーマンスを確認します。
  2. 私はこのコードでテストしました:

// テストページ

<?php

    $strSmall = "ये एक हिन्दी वाक्य है, इसमे बहुत सारे शब्द हैं |";
    $strBig = implode(".",array_fill(0,100,$strSmall));  // Create a big string

    $tStart = microtime(true);
    echo cutString($strBig);
    $tEnd = microtime(true);

    echo "\nTime taken:" , ($tEnd - $tStart) , " s";

    // multibyte wordcutter
    function cutString( $string , $width = 20 , $cut=false ){
        if( mb_strlen( $string , "UTF-8" ) == 0 ){
            return $string;
            }
        $input = $string;
        if ( mb_strlen( $string , "UTF-8" ) > $width ) {
            $string = mb_wordwrap( $string , $width , "\n" , $cut );
            $string = mb_substr( $string , 0 , mb_strpos( $string , "\n" , NULL , "UTF-8" ) , "UTF-8" );
            if( mb_strlen( $string , "UTF-8" ) > $width ) {
                $string = mb_wordwrap( $string , $width , "\n" , true );
                $string = mb_substr( $string , 0 , mb_strpos( $string , "\n" , NULL , "UTF-8" ) , "UTF-8" );
                }
            elseif( mb_strlen( $string , "UTF-8" ) == 0 ){
                $string = mb_wordwrap( $input , $width , "\n" , true );
                $string = mb_substr( $string , 0 , mb_strpos( $string , "\n" , NULL , "UTF-8" ) , "UTF-8" );
                }
            }
        return $string;
        }




  // multibyte safe wordwrap
function mb_wordwrap($string, $width = 75, $break = "\n", $cut = false, $charset = 'utf-8')
{

$stringWidth = iconv_strlen($string, $charset);
$breakWidth  = iconv_strlen($break, $charset);

    if (strlen($string) === 0) {
        return '';
    } elseif ($breakWidth === null) {
        throw new Zend_Text_Exception('Break string cannot be empty');
    } elseif ($width === 0 && $cut) {
        throw new Zend_Text_Exception('Can\'t force cut when width is zero');
    }

    $result    = '';
    $lastStart = $lastSpace = 0;

    for ($current = 0; $current < $stringWidth; $current++) {
        $char = mb_substr($string, $current, 1, $charset);

        if ($breakWidth === 1) {
            $possibleBreak = $char;
        } else {
            $possibleBreak = mb_substr($string, $current, $breakWidth, $charset);
        }

        if ($possibleBreak === $break) {
            $result    .= mb_substr($string, $lastStart, $current - $lastStart + $breakWidth,charset);
            $current   += $breakWidth - 1;
            $lastStart  = $lastSpace = $current + 1;
        } elseif ($char === ' ') {
            if ($current - $lastStart >= $width) {
                $result    .= mb_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
                $lastStart  = $current + 1;
            }

            $lastSpace = $current;
        } elseif ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
            $result    .= mb_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
            $lastStart  = $lastSpace = $current;
        } elseif ($current - $lastStart >= $width && $lastStart < $lastSpace) {
            $result    .= mb_substr($string, $lastStart, $lastSpace - $lastStart, $charset) . $break;
            $lastStart  = $lastSpace = $lastSpace + 1;
        }
    }

    if ($lastStart !== $current) {
        $result .= mb_substr($string, $lastStart, $current - $lastStart, $charset);
    }
    return $result;
}

?>
  1. 約200ミリ秒かかりました。

    パフォーマンス テストの所要時間: 0.23847889900208 秒

  2. iconv_strlenこれは xdebug プロファイリングの結果です。時間の無駄であることがわかりますmb_substr

ここに画像の説明を入力

. コードを簡単にするために非常に多くの関数呼び出しを行う代わりに、関数呼び出しを最小限に抑え、いくつかの独自のループを記述してください。

于 2012-12-06T08:26:45.573 に答える