1

SEARCH TERM の前後の文字数を厳密にカウントして文字列全体を切り捨てる検索結果があります。残念ながら、これにより、出力の途中で単語が途切れてしまいます。(...カウントの前後に楕円を付けて)

検索結果で、空白と単語の途中でのみ完全な文字列が切り取られるようにしようとしています。

関数は次のとおりです。

private function _highlight_results(){

    $GLOBALS['_SEARCH_SUMMARY_LENGTH'] = 24;

    foreach($this->results as $url => &$this_result){
        if(!$this_result['url_display'] && $this_result['url']){
            $this_result['url_display'] = $this_result['url'];
        }
        foreach($this_result['search_term'] as $search_term){
            $search_term = preg_quote($search_term,'/');

            foreach(array('title','summary','url_display') as $highlight_item){
                if($this_result[$highlight_item] && preg_match('/'.$search_term.'/i',$this_result[$highlight_item])){
                    if($highlight_item != 'url_display' && strlen($this_result[$highlight_item]) > $GLOBALS['_SEARCH_SUMMARY_LENGTH']){
                        $boobs = ceil(($GLOBALS['_SEARCH_SUMMARY_LENGTH']-strlen($this->_search_term))/2);
                        preg_match('/(.{0,'.$boobs.'})('.$search_term.')(.{0,'.$boobs.'})/i',$this_result[$highlight_item],$matches);
                        // want to even out the strings a bit so if highlighted term is at end of string, put more characters infront.
                        $before_limit = $after_limit = ($boobs - 2);
                        if(strlen($matches[1])>=$before_limit && strlen($matches[3])>=$after_limit){
                            // leave limit alone.
                        }else if(strlen($matches[1])<$before_limit){
                            $after_limit += $before_limit - strlen($matches[1]);
                            $before_limit = strlen($matches[1]);
                            preg_match('/(.{0,'.($before_limit+2).'})('.$search_term.')(.{0,'.($after_limit+2).'})/i',$this_result[$highlight_item],$matches);
                        }else if(strlen($matches[3])<$after_limit){
                            $before_limit += $after_limit - strlen($matches[3]);
                            $after_limit = strlen($matches[3]);
                            preg_match('/(.{0,'.($before_limit+2).'})('.$search_term.')(.{0,'.($after_limit+2).'})/i',$this_result[$highlight_item],$matches);
                        }
                        $this_result[$highlight_item] = (strlen($matches[1])>$before_limit) ? '...'.substr($matches[1],-$before_limit) : $matches[1];
                        $this_result[$highlight_item] .= $matches[2];
                        $this_result[$highlight_item] .= (strlen($matches[3])>$after_limit) ? substr($matches[3],0,$after_limit).'...' : $matches[3];

                    }

                }else if(strlen($this_result[$highlight_item]) > $GLOBALS['_SEARCH_SUMMARY_LENGTH']){
                    $this_result[$highlight_item] = substr($this_result[$highlight_item],0,$GLOBALS['_SEARCH_SUMMARY_LENGTH']).'...';
                }
            }
        }

        foreach($this_result['search_term'] as $search_term){
            $search_term = preg_quote($search_term,'/');

            foreach(array('title','summary','url_display') as $highlight_item){
                $this_result[$highlight_item] = preg_replace('/'.$search_term.'/i','<span id="phpsearch_resultHighlight">$0</span>',$this_result[$highlight_item]);
            }
        }
    }
}

これが私が考えていたことです...文字列出力を表示する直前に、スクリプトは、楕円と直接の文字を「検索」する関数を使用して文字列をループし、その後文字を削除し、空白が現れるまでループを続ける必要があります見つかった。次に、次のループで文字と楕円を「検索」し、文字を削除して、楕円の前に空白が見つかるまでループを続けます。

上記の私の説明の非常に悲しい疑似コードを次に示します。

WHILE (not the end of the string) {
 // NOT SURE IF I NEED A FOREACH LOOP HERE TO CHECK EACH CHAR
    IF ( ^ ('...' and an immediate char are found) ) {
           delete chars until a white space is found;

            // if '...' is deleted along with the chars, then put the '...' back in:
            //string .= '...' . string;
    }
    IF ( $ (a char and an immediate '...' are found) ) {
           delete chars until a white space is found;

            // if '...' is deleted along with the chars, then put the '...' back in:
            //string .= string . '...';
    }
}
PRINT string;

上記の内容から、私が探しているもののアイデアを得ることができると思います。wordwrap() を調査してテストしましたが、まだ答えが見つかりません。

4

1 に答える 1

0

これは、うまく機能し、非常にパフォーマンスが高いアプローチです。唯一の欠点は、そのままではスペースでのみ単語を分割することです。strrspn補完する機能がないため、これを自明に修正することはできませんstrspn(ただし、このソリューションを拡張するために簡単に記述して使用することができます)。

function display_short($str, $limit, $ellipsis = '...') {
    // if all of it fits there's nothing to do
    if (strlen($str) <= $limit) {
        return $str;
    }

    // $ellipsis will count towards $limit
    $limit -= strlen($ellipsis);

    // find the last space ("word boundary")
    $pos = strrpos($str, ' ', $limit - strlen($str));

    // if none found, prefer breaking into the middle of
    // "the" word instead of just giving up
    if ($pos === false) {
        $pos = $limit;
    }

    return substr($str, 0, $pos).$ellipsis;
}

テスト:

$string = "the quick brown fox jumps over the lazy dog";
for($limit = 10; $limit <= strlen($string); $limit += 10) {
    print_r(display_short($string, $limit));
}

実際に見てください

于 2012-04-25T08:59:05.037 に答える