简体   繁体   中英

Need a scalable way to Limit Content by using substr() and strpos() in PHP

I am using Markdown to render a rich content on a page, using PHP. For the brief version, I think it would be fine to truncate the content till second paragraph, or technically, after two \\r\\n have crossed. So I used this code:

substr($content, 0, strpos($content, "\r\n\r\n", strpos($content, "\r\n\r\n") + 1));

Since the count of \\r\\n is hard coded, and is also calculated in a weird way, (using +1 after the first position and stuff) , is there a better way I can make a function, which says limitContent($content, $lines = 2) and passing the number of lines to the $lines parameter, as by default, it truncates to two lines?

My current code is:

/**
 * Break down the content of Markdown upto 2 breaks. 
 * @param string Markdown String
 * @return string Markdown String upto 2 breaks
 */
function limitContent($content)
{
    return substr($content, 0, strpos($content, "\r\n\r\n", strpos($content, "\r\n\r\n") + 1));
}

Thanks in advance.

You could use explode() for that:

join("\r\n", array_slice(explode("\r\n\r\n", $content, $lines + 1), 0, $lines));

Or similarly, using preg_split() - to match both LF and CRLF:

join("\r\n", array_slice(preg_split("/(?:\r?\n){2}/", $content, $lines), 0, $lines));

Above solutions are not very memory efficient though, because the full content after the last match is copied into the last array element.

You could also use strtok() as this might be more memory efficient:

$result = '';
for ($i = 0, $tok = strtok($s, "\r\n\r\n"); false !== $tok && $i < $lines; ++$i, $tok = strtok("\r\n\r\n")) {
        $result .= $t . PHP_EOL;
}

Ok, I misunderstood. Is this what you want?

function limitContent($content, $lines=2)
{
    $tmp=explode("\r\n\r\n", $content);
    $tmp=array_slice($tmp,0,$lines);
    return implode("\r\n", $tmp);
}

[edit] And slightly better would be:

function limitContent($content, $lines=2)
    {
        $tmp=explode("\r\n\r\n", $content, $lines+1);
        unset($tmp[$lines]);
        return implode("\r\n", $tmp);
    }

I was interessted in the performance difference between both options in Nin's answer so I started a quick check with some data I had at hand. I tested against 2 string: a long string with many paragraphs and one long string with 2 paragraphs.

Option 2 turn out to be 14 times faster on the first string and 6% faster on the second string. So this has a huge advantage on the first string.

Moreover I turned Praveen Kumar's initial idea into a simple loop based version and tested it:

function limitContent($content, $lines=2) {
    $pos = -1;
    for ($i = 0; $i < $lines; $i++) {
        $pos = strpos($content, "\r\n\r\n", $pos+1);
        if ($pos === false) return $content;
    }
    return substr($content, 0, $pos);
}

This version turned out to be another 178 times faster on the first string and another 25 times faster on the second string. While these numbers might change a lot for you depending on data and php version I think it clearly shows that converting to an array and back is slow. I'd probably still use Nin's idea if performance is not a concern because it's pretty straight forward to read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM