题目是:
假设有"123<em>abc</em>456<em>def</em>789"这么一个字符串,写一个函数,可以传入一个字符串,和一个要截取的长度。返回截取后的结果。要求:
1 <em>和</em>标记不得计算在长度之内。
2 截取后的字符串,要保留原有<em>标签,不过如果最后有一个标签没有闭合,则去掉其开始标签。示例:
题中的字符串,要截取长度5,则返回的字符串应该为:123ab,要截取长度8,应返回123<em>abc</em>45。
<?php
// QQ群:23930992
function find($str, $size, &$string, &$number, &$saveString, &$newString) // 查找标签,当 PHP > 5.3 可以把注释去掉
{
    $i=$j=0;
    while(strlen($saveString)<$size)
    {
        //loop:
        if($str[$i] == '<')
        {
            $k=0;
            $number[$j][$k++]=$i;
            $string[$j]='';
            do
            {
                $string[$j].=$str[$i];
                if($str[$i] == '>')
                {
                    $number[$j++][$k++]=$i;
                    break;
                }
            }while($str[$i++] != '>');
        }
        else
        {
            $saveString.=$str[$i];
            /*if(strlen($saveString) == $size)
            {
                if($str[++$i] =='<')
                {
                    goto loop;
                }
                $i--;
            }*/
        }
        $i++;
    }
    for($j=0; $j<$i; $j++)
    {
        $newString.=$str[$j];
    }
}function filter($str)  // 过滤标签,然后进行比较
{
    $newstr    = '';
    $strLength = strlen($str);
    for($i=0;$i<$strLength;$i++)
    {
        switch($str[$i])
        {
            case '<' : continue;
            case '/' : continue;
            case '>' : continue;
            case ' ' : break;
            default  : $newstr .= $str[$i];
        }
    }
    return $newstr;
}function deleteReservedTag(&$string, &$number, $reserved) // 从标签组里去除 保留标签
{
$stringLength   = count($string);
$reservedLength = count($reserved);
    for($i=0; $i<$stringLength;$i++)      // 去掉保留标签部分
    {
        for($j=0;$j < $reservedLength;$j++)
        {
            if( filter($string[$i]) == filter($reserved[$j]) )
            {
                $string[$i] = NULL;
                for($k=0;$k<2;$k++)
                {
                    $number[$i][$k] = NULL;
                }
            }
        }
    }
    $tempString[]    = '';
    $tempNumber[][]  = 0;
    for($i=0,$j=0; $i < $stringLength; $i++) // 把空的地方填补
    {
        if($string[$i] != NULL)
        {
            $tempString[$j]=$string[$i];
            for($k=0;$k<2;$k++)
            {
                $tempNumber[$j][$k] = $number[$i][$k];
            }
            $j++;
        }
    }
    $string = $tempString;
    $number = $tempNumber;
}function compare(&$string, &$number)     //比较成对标签
{
$stringLength = count($string);
    for($i=0; $i < $stringLength; $i++)  //删除成对标签
    {
        for($j = $i+1; $j < $stringLength; $j++)
        {
            if( filter($string[$i]) == filter($string[$j]) )
            {
                $string[$i] = NULL;
                $string[$j] = NULL;
                for($k=0;$k<2;$k++)
                {
                    $number[$i][$k] = NULL;
                }
                for($k=0;$k<2;$k++)
                {
                    $number[$j][$k] = NULL;
                }
            }
        }
    }
    $tempString[]    = '';
    $tempNumber[][]  = 0;
    for($i=0,$j=0; $i < $stringLength; $i++) // 把空的地方填补
    {
        if($string[$i] != NULL)
        {
            $tempString[$j]=$string[$i];
            for($k=0;$k<2;$k++)
            {
                 $tempNumber[$j][$k] = $number[$i][$k];
            }
            $j++;
        }
    }
    $string = $tempString;
    $number = $tempNumber;
}function replace(&$string, $number, $newString)
{
    $tempString       = '';
    $saveStringLength = strlen($newString);
    $stringLength     = count($string);
    //echo $saveStringLength."\n".$stringLength;
    for($i=0, $j=0; $i < $saveStringLength; $i++)
    {
        if( $j < $stringLength )
        {
            if( $i == $number[$j][0])
            {
                $begin = $number[$j][1] - $number[$j][0];
                while($begin)
                {
                    $begin--;
                    $i++;
                }
               $j++;
               $i++;
            }
        }
       $tempString .= $newString[$i];
    }
    $string = $tempString;
}$str = '<p align="center"><b>123<br /><em>abc</em>45<hr />6</b>defg<i>789</i></p>';
$size=15;
$reserved = array //保留标签
(
    '<br />',
    '<br>',
    '<hr />',
    '<hr>'
);
$string[]='';                                                  // 保存所有标签
$number[][]=0;                                                 // 保存所有标签位置
$saveString = '';                                              // 保存截取标签后的所有字符串
$newString  = '';                                              // 保存所有未截取标签的字符串
find($str, $size, $string, $number, $saveString, $newString);  // 查找标签
deleteReservedTag($string, $number, $reserved);                // 从标签组里去除 保留标签
compare($string, $number);                                     // 从标签组里去除 成对标签
replace($string, $number, $newString);printf("截取长度:%d\n\n", $size);
printf("完整长度:%s\n\n",$str);
printf("处理结果:%s\n\n", $string);
printf("截取长度:%s (%s)\n\n",$saveString,strlen($saveString));
printf("未处理前:%s\n",$newString);
?>运算结果如下
------------------------------------------------------------------------------------
截取长度:15完整长度:<p align="center"><b>123<br /><em>abc</em>45<hr />6</b>defg<i>789</i></p>处理结果:<b>123<br /><em>abc</em>45<hr />6</b>defg78截取长度:123abc456defg78 (15)未处理前:<p align="center"><b>123<br /><em>abc</em>45<hr />6</b>defg<i>78

解决方案 »

  1.   

    P4+768MB 机运行速度如下内存使用情况:2176
    算法运行时间(microtime):0.0012378692626953
      

  2.   

    欢迎各位 PHP 爱好者来  QQ群:23930992
      

  3.   

    程序处理一些特殊数据的时候会出问题,请把代码粘贴到上面function filter($str)  // 过滤标签,然后进行比较
    {
        $newstr    = '';
        $strLength = strlen($str);
        for($i=0;$i<$strLength;$i++)
        {
            switch($str[$i])
            {
                case '<' : continue;
                case '/' : continue;
                case '>' : continue;
                case ' ' : break 2;
                default  : $newstr .= $str[$i];
            }
        }
        return $newstr;
    }
      

  4.   

    又修正一个错误,请把下面代码粘贴到上面function replace(&$string, $number, $newString)
    {
        $tempString       = '';
        $saveStringLength = strlen($newString);
        $stringLength     = count($string);
        for($i=0, $j=0; $i < $saveStringLength; $i++)
        {
            if( $j < $stringLength )
            {
                if( $i == $number[$j][0])
                {
                    $begin = $number[$j][1] - $number[$j][0];
                    while($begin)
                    {
                        $begin--;
                        $i++;
                    }
                   $j++;
                }
            }
            else
            {
               $tempString .= $newString[$i];
            }
        }
        $string = $tempString;
    }
      

  5.   

    完整修改后的代码<?php
    // QQ群:23930992
    function find($str, $size, &$string, &$number, &$saveString, &$newString) // 查找标签,当 PHP > 5.3 可以把注释去掉
    {
        $i=$j=0;
        while(strlen($saveString)<$size)
        {
            //loop:
            if($str[$i] == '<')
            {
                $k=0;
                $number[$j][$k++]=$i;
                $string[$j]='';
                do
                {
                    $string[$j].=$str[$i];
                    if($str[$i] == '>')
                    {
                        $number[$j++][$k++]=$i;
                        break;
                    }
                }while($str[$i++] != '>');
            }
            else
            {
                $saveString.=$str[$i];
                /*if(strlen($saveString) == $size)
                {
                    if($str[++$i] =='<')
                    {
                        goto loop;
                    }
                    $i--;
                }*/
            }
            $i++;
        }
        for($j=0; $j<$i; $j++)
        {
            $newString.=$str[$j];
        }
    }function filter($str)  // 过滤标签,然后进行比较
    {
        $newstr    = '';
        $strLength = strlen($str);
        for($i=0;$i<$strLength;$i++)
        {
            switch($str[$i])
            {
                case '<' : continue;
                case '/' : continue;
                case '>' : continue;
                case ' ' : break 2;
                default  : $newstr .= $str[$i];
            }
        }
        return $newstr;
    }function deleteReservedTag(&$string, &$number, $reserved) // 从标签组里去除 保留标签
    {
    $stringLength   = count($string);
    $reservedLength = count($reserved);
        for($i=0; $i<$stringLength;$i++)      // 去掉保留标签部分
        {
            for($j=0;$j < $reservedLength;$j++)
            {
                if( filter($string[$i]) == filter($reserved[$j]) )
                {
                    $string[$i] = NULL;
                    for($k=0;$k<2;$k++)
                    {
                        $number[$i][$k] = NULL;
                    }
                }
            }
        }
        $tempString[]    = '';
        $tempNumber[][]  = 0;
        for($i=0,$j=0; $i < $stringLength; $i++) // 把空的地方填补
        {
            if($string[$i] != NULL)
            {
                $tempString[$j]=$string[$i];
                for($k=0;$k<2;$k++)
                {
                    $tempNumber[$j][$k] = $number[$i][$k];
                }
                $j++;
            }
        }
        $string = $tempString;
        $number = $tempNumber;
    }function compare(&$string, &$number)     //比较成对标签
    {
    $stringLength = count($string);
        for($i=0; $i < $stringLength; $i++)  //删除成对标签
        {
            for($j = $i+1; $j < $stringLength; $j++)
            {
                if( filter($string[$i]) == filter($string[$j]) )
                {
                    $string[$i] = NULL;
                    $string[$j] = NULL;
                    for($k=0;$k<2;$k++)
                    {
                        $number[$i][$k] = NULL;
                    }
                    for($k=0;$k<2;$k++)
                    {
                        $number[$j][$k] = NULL;
                    }
                }
            }
        }
        $tempString[]    = '';
        $tempNumber[][]  = 0;
        for($i=0,$j=0; $i < $stringLength; $i++) // 把空的地方填补
        {
            if($string[$i] != NULL)
            {
                $tempString[$j]=$string[$i];
                for($k=0;$k<2;$k++)
                {
                     $tempNumber[$j][$k] = $number[$i][$k];
                }
                $j++;
            }
        }
        $string = $tempString;
        $number = $tempNumber;
    }function replace(&$string, $number, $newString)
    {
        $tempString       = '';
        $saveStringLength = strlen($newString);
        $stringLength     = count($string);
        for($i=0, $j=0; $i < $saveStringLength; $i++, $j=0)
        {
            while( $j < $stringLength )
            {
                if( $i == $number[$j][0])
                {
                    $i = $number[$j][1];
                    $i++;
                }
                $j++;
            }
            $tempString .= $newString[$i];
        }
        $string = $tempString;
    }$sttime = microtime(true);
    $stmem = memory_get_usage();
    $str = '
            <table id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_htmlShop" width="99%" border="0" cellspacing="0" cellpadding="0">
    <tr>
    <td valign="top"><img id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_imgShopLogo" src="http://auction.ename.cn/images/nopic.gif" style="height:74px;width:98px;border-width:0px;" /></td>
    <td><h5>364867的玉米小店</h5>
                    买家信用:<a id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_hlBuyerCreditLink" title="0" href="/Customer/UserEvaluate.aspx?uid=364867&amp;from=seller" target="_blank">0<span class="goodssaletitle2"></span></a><br />
                    卖家好评率:100.00%<br />
                    买家好评率:0.00%<br />
                    注册时间:2010年04月29日<br />
                    <div style="width:230px">荣誉资质:<img ></div>
                    <div><a id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_hlShopUrl" href="http://364867.shop.ename.cn"><img src="/images/scicon.gif" width="117" height="34" border="0" /></a></div></td>
    </tr>
    </table>        
            </td>
          </tr>
          <tr>
            <td class="shopbg04">&nbsp;</td>
          </tr>
        </table>
    ';$size=160;
    $reserved = array //保留标签
    (
        '<br />',
        '<br>',
        '<hr />',
        '<hr>',
        '<img />',
        '<img>'
    );
    $string[]='';                                                  // 保存所有标签
    $number[][]=0;                                                 // 保存所有标签位置
    $saveString = '';                                              // 保存截取标签后的所有字符串
    $newString  = '';                                              // 保存所有未截取标签的字符串
    find($str, $size, $string, $number, $saveString, $newString);  // 查找标签
    deleteReservedTag($string, $number, $reserved);                // 从标签组里去除 保留标签
    compare($string, $number);                                     // 从标签组里去除 成对标签
    replace($string, $number, $newString);printf("截取长度:%d\n\n", $size);
    printf("完整长度:%s\n\n",$str);
    printf("处理结果:%s\n\n", $string);
    printf("截取长度:%s (%s)\n\n",$saveString,strlen($saveString));
    printf("未处理前:%s\n",$newString);echo "内存使用情况:",(memory_get_usage()-$stmem),"\n";echo "算法运行时间(microtime):",(microtime(true)-$sttime),"\n";?>
    截取长度:160
    完整长度:
            <table id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_htmlShop" width="99%" border="0" cellspacing="0" cellpadding="0">
    <tr>
    <td valign="top"><img id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_imgShopLogo" src="http://auction.ename.cn/images/nopic.gif" style="height:74px;width:98px;border-width:0px;" /></td>
    <td><h5>364867的玉米小店</h5>
                    买家信用:<a id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_hlBuyerCreditLink" title="0" href="/Customer/UserEvaluate.aspx?uid=364867&amp;from=seller" target="_blank">0<span class="goodssaletitle2"></span></a><br />
                    卖家好评率:100.00%<br />
                    买家好评率:0.00%<br />
                    注册时间:2010年04月29日<br />
                    <div style="width:230px">荣誉资质:<img ></div>
                    <div><a id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_hlShopUrl" href="http://364867.shop.ename.cn"><img src="/images/scicon.gif" width="117" height="34" border="0" /></a></div></td>
    </tr>
    </table>        
            </td>
          </tr>
          <tr>
            <td class="shopbg04">&nbsp;</td>
          </tr>
        </table>处理结果:
            

    <td valign="top"><img id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_imgShopLogo" src="http://auction.ename.cn/images/nopic.gif" style="height:74px;width:98px;border-width:0px;" /></td>
    <h5>364867的玉米小店</h5>
                    买家信用:<a id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_hlBuyerCreditLink" title="0" href="/Customer/UserEvaluate.aspx?uid=364867&amp;from=seller" target="_blank">0<span class="goodssaletitle2"></span></a><br />
                    卖家好评率:100.00%<br />
                    买家好评率:0.00%<br />
                    注册截取长度:
            


    364867的玉米小店
                    买家信用:0
                    卖家好评率:100.00%
                    买家好评率:0.00%
                    注册 (160)
    未处理前:
            <table id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_htmlShop" width="99%" border="0" cellspacing="0" cellpadding="0">
    <tr>
    <td valign="top"><img id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_imgShopLogo" src="http://auction.ename.cn/images/nopic.gif" style="height:74px;width:98px;border-width:0px;" /></td>
    <td><h5>364867的玉米小店</h5>
                    买家信用:<a id="ctl00_ContentPlaceHolder1_BidDomainName1_Shop1_hlBuyerCreditLink" title="0" href="/Customer/UserEvaluate.aspx?uid=364867&amp;from=seller" target="_blank">0<span class="goodssaletitle2"></span></a><br />
                    卖家好评率:100.00%<br />
                    买家好评率:0.00%<br />
                    注册
    内存使用情况:5096算法运行时间(microtime):0.0040628910064697
      

  6.   

    精简后的代码<?php
    // QQ群:23930992
    function find($str, $size, &$string, &$number, &$saveString, &$newString) // 查找标签并保存到标签组
    {
        $i=$j=0;
        while(strlen($saveString)<$size)
        {
            if($str[$i] == '<')
            {
                $k=0;
                $number[$j][$k++]=$i;
                $string[$j]='';
                do
                {
                    $string[$j].=$str[$i];
                    $i++;
                }while($str[$i] != '>');
                $number[$j++][$k]=$i;
            }
            else
            {
                $saveString.=$str[$i];
            }
            $i++;
        }
        for($j=0; $j<$i; $j++)
        {
            $newString.=$str[$j];
        }
    }function filter($str)  // 过滤标签,然后进行比较
    {
        $newstr    = '';
        $strLength = strlen($str);
        for($i=0;$i<$strLength;$i++)
        {
            switch($str[$i])
            {
                case '<' : continue;
                case '/' : continue;
                case '>' : continue;
                case ' ' : break 2;
                default  : $newstr .= $str[$i];
            }
        }
        return $newstr;
    }function deleteReservedTag(&$string, &$number, $reserved) // 从标签组里去除 保留标签
    {
        $stringLength   = count($string);
        $reservedLength = count($reserved);
        for($i=0; $i<$stringLength;$i++)      // 去掉保留标签部分
        {
            for($j=0;$j < $reservedLength;$j++)
            {
                if( filter($string[$i]) == filter($reserved[$j]) )
                {
                    $string[$i] = NULL;
                    for($k=0;$k<2;$k++)
                    {
                        $number[$i][$k] = NULL;
                    }
                }
            }
        }
    }function compare(&$string, &$number)     //比较成对标签
    {
        $stringLength = count($string);
        for($i=0; $i < $stringLength; $i++)  //删除成对标签
        {
            for($j = $i+1; $j < $stringLength; $j++)
            {
                if( filter($string[$i]) == filter($string[$j]) )
                {
                    $string[$i] = $string[$j] = NULL;
                    for($k=0;$k<2;$k++)
                    {
                        $number[$i][$k] = $number[$j][$k] = NULL;
                    }
                }
            }
        }
        
        //begin 把标签组空的地方 填补 (你可以去除本小段代码,代价是运行时间增加了)
        $tempString[]    = '';
        $tempNumber[][]  = 0;
        for($i=0,$j=0; $i < $stringLength; $i++)
        {
            if($string[$i] != NULL)
            {
                $tempString[$j]=$string[$i];
                for($k=0;$k<2;$k++)
                {
                     $tempNumber[$j][$k] = $number[$i][$k];
                }
                $j++;
            }
        }
        $string = $tempString;
        $number = $tempNumber;
        //end
    }function replace(&$string, $number, $newString) // 核心代码 ...
    {
        $tempString       = '';
        $saveStringLength = strlen($newString);
        $stringLength     = count($string);
        for($i=0, $j=0; $i < $saveStringLength; $i++, $j=0)
        {
            while( $j < $stringLength )
            {
                if( $i == $number[$j][0])
                {
                    $i = $number[$j][1];
                    $i++;
                }
                $j++;
            }
            $tempString .= $newString[$i];
        }
        $string = $tempString;
    }$sttime = microtime(true);
    $stmem = memory_get_usage();$str = '<p align="center"><b>123<br /><em>abc</em>45<hr />6</b>d<strong>efg<i>789</i></strong></p>';$size=15;
    $reserved = array //保留标签
    (
        '<br />',
        '<br>',
        '<hr />',
        '<hr>',
        '<img />',
        '<img>'
    );
    $string[]='';                                                  // 保存所有标签
    $number[][]=0;                                                 // 保存所有标签位置
    $saveString = '';                                              // 保存截取标签后的所有字符串
    $newString  = '';                                              // 保存所有未截取标签的字符串
    find($str, $size, $string, $number, $saveString, $newString);  // 查找标签
    deleteReservedTag($string, $number, $reserved);                // 从标签组里去除 保留标签
    compare($string, $number);                                     // 从标签组里去除 成对标签
    //deleteSpaceArray($string, $number);                          // 删除标签组里空下来的空间
    //deleteSpaceArray($string, $number);                          // 删除标签组里空下来的空间
    replace($string, $number, $newString);printf("截取长度: %u\n\n", $size);
    printf("完整长度: %s\n\n", $str);
    printf("截取长度: %s  (%u)\n\n", $saveString, strlen($saveString));
    printf("处理结果: %s\n\n", $string);
    printf("未处理前: %s\n\n", $newString);printf("内存使用情况:%u\n", memory_get_usage()-$stmem);
    printf("算法运行时间(microtime): %f\n", microtime(true)-$sttime);?>
      

  7.   

    $s = '123<em>abc</em>456<em>def</em>789<em>def</em>789<em>def</em>789<em>def</em>789';function subs($s, $len){//此函数参数有二:$s - 源字符串,    $len - 要截取的长度        (当让你也可以将标签传进来,不过要进行其他操作)
        $s1 = $s;
        $s1 = preg_replace('/<\/?em>/s', '', $s1);
        $sub = mb_substr($s1, 0, $len, 'gbk');    //处理成数组
        $s2 = $s;
        $s2 = preg_replace('/<\/?em>/s', '[p]', $s2);
        $arr = explode('[p]', $s2);
        $arr1 = $arr2 = array();
        $num = count($arr);
        $num1 = $num2 = 0;
        $bs = 0;
        for($i = 0; $i < $num; $i++){
            $arr1[] = strlen($arr[$i]);
            $num2 = array_sum($arr1);
            if($num2 >= $len){
                $num1 = $len - $num2 + strlen($arr[$i]);
                if($num1 != strlen($arr[$i]))$bs = 1
                $s3 = mb_substr($arr[$i], 0, $num1, 'gbk');
                $arr[$i] = $s3;
                $arr2 = array_slice($arr, 0, $i + 1);
                break;
            }
        }    //处理数组,结合成所需要的成字符串
        $num = count($arr2);
        $s4 = '';
        for($i =  0; $i < $num; $i++){
            if($i % 2 == 0){
                if(($i + 1 == $num && $bs == 1) || ($i + 2 == $num && $bs == 1) || ($num % 2 == 1 && $i + 1 == $num)){
                    $s4 .= $arr2[$i];
                }else{
                    $s4 .= $arr2[$i]."&lt;em&gt;";
                }
            }else{
                if($i + 1 == $num && $bs == 1){
                    $s4 .= $arr2[$i];
                }else{
                    $s4 .= $arr2[$i]."&lt;/em&gt;";
                }
            }
        }
        //返回结果
        return $s4;
    }
    $s = subs($s, 17);
    echo $s;