Convert br tags to span tags

Have you ever needed to convert the string immediately before br tags and wrap it in span tags instead? Me too.

There is very likely a regex solution but here’s a very simple way to achieve it using string and array functions.

/**
 * Replace linebreaks with span tags
 *
 * Wraps each string immediately before a linebreak in span tags and removes the linebreak.
 *
 * @param string $string        Original string that may have linebreaks (\r\n\
\
)
 * @param string $span_class    Styling class for span tags
 * @return string               HTML string with linebreaks replaced with span tags
 */
function nl2span($string = '', $span_class = 'span') : string {
    // standardise line breaks
    $nl = "\n";
    $string = str_replace(["\r\n", "\r", "
", "
"], $nl, $string );

    // just return the original string if there aren't any linebreaks
    if (!str_contains($string, $nl)) return $string;

    // remove contiguous linebreaks
    $string = preg_replace( "/$nl+/", $nl, $string );

    // convert string to array of parts
    $string_to_array = explode($nl, $string);

    // pop the last part as it will not be wrapped in a span
    $after_nl = array_pop($string_to_array);

    // declare var for spanned elements
    $array_to_string = '';

    // build spanned elements
    foreach ($string_to_array as $index => $part) {
        // create a unique span class for each part
        $unique_span = (int) $index + 1;
        $array_to_string .= sprintf(
            '<span class="%1$s %1$s-%2$s">%3$s</span>',
            $span_class,
            $unique_span,
            $part);
    }

    // cleanup (if you feel the need)
    unset($nl, $string, $string_to_array);

    // append the last part and return
    return $array_to_string . $after_nl;
}

Side note:

str_contains is an Illuminate helper function (and PHP8). If you don’t use this Illuminate or PHP8, then replace it in the code above with the following:

// just return the original string if there aren't any linebreaks
$has_breaks = false;
foreach ((array) $string as $needle) {
    if ($needle !== '' && mb_strpos($string, $needle) !== false) {
        $has_breaks = true;
    }
}
if (!$has_breaks) return $string; 

Conclusion

So there it is. If you ever come across the odd occasion where you need to wrap the string immediately before a break tag with span tag, then just drop this into your project’s PHP code and you’re good to go! Or get in touch and we’ll gladly assist.