views:

113

answers:

2

I'm trying to replace a set of characters within a string. The string may or may not have any data to change. The string is marked up in a way that allows for it to change it's color from a set of characters. The string can reset it's formatting to default by using a defined set of characters.

This setup is very much like the ECMA-48 standard used on LINUX consoles for colors and other special effects.

Where one string could be ^0Black^1Red^2Green^3Yellow^4Blue^5Purple^6Cyan^7White Producing the following HTML:

<span style="color: #000">Black</span><span style="color: #F00">Red</span><span style="color: #0F0">Green</span><span style="color: #FF0">Yellow</span><span style="color: #00F">Blue</span><span style="color: #F0F">Purple</span><span style="color: #0FF">Cyan</span><span style="color: #FFF">White</span>

Another string (^1Error^8: ^3User Error) could also produce:

<span style="color: #F00">Error</span>: <span style="color: #FF0">User Error</span>

You might of noticed the ^8 part of that string resets the color for that part of the string.

What's the best way to go about parsing these kinds of strings?

+3  A: 

I'd use preg_replace_callback. Since there is additional data required in the callback, it would be practical to put it all together in a class, like this:

class Escaper
{
    function __construct() {
        $this->colors = array(
            0 => "#000",
            1 => "#00F", 
            //etc
        );
    }

    function replace_color($m) {
        list(, $color, $text) = $m;
        return isset($this->colors[$color]) ?
            "<span style='color:{$this->colors[$color]}'>{$text}</span>" :
            $text;
    }

    function apply($text) {
        $text = preg_replace_callback('~\^(\d+)([^^]+)~', array($this, 'replace_color'), $text);
        // more escapes to process?

        return $text;
    }
}

//

 $e = new Escaper; 
 $convertedText = $e->apply($sourceText);
stereofrog
Thank you for your answer, it has provided me with some things to think about. I myself went the straight up function route to provide some better basic functionality to the core of PHP.
Mark Tomlin
A: 

I created the str_inject function, as follows:

<?php

/* Function Calls */
// Inject one string into another at a specific point.
function str_inject($sourceStr, $injectStr, $injectPos)
{
    if ($injectPos >= strlen($sourceStr)) {
        trigger_error('Inject posisition is greater then the length of the source string, concating string!', E_USER_NOTICE);
        return str_pad($sourceStr, $injectPos) . $injectStr;
    }

    return substr($sourceStr, 0, $injectPos) . $injectStr . substr($sourceStr, $injectPos);
}

/* Example Strings */
#        0123456789012345
$str1 = 'This is a string';
$str2 = ' just';

/* Example Output */
// Example 1: Proper Useage.
$str = str_inject($str1, $str2, 7);
echo $str . PHP_EOL; # echos: 'This is just a string';

// Example 2: Inproper Useage.
$str = str_inject($str1, $str2, 16);
echo $str . PHP_EOL; # echos: 'This is a string just';

// Example 3: Non Hidden, Short Hand, ECMA-48 Colours
# Make ECMA-48 of Strings.
$ecma48 = array();
for ($i = 0; $i < 8; ++$i)
{
    $ecma48[$i] = "\033[3{$i}m";
}
$ecma48[] = "\033[39m"; # Reset Forground Color
$ecma48[] = "\033[0m"; # Reset All

# Setting up Varables
$str = '^1Red^8Reset Color'; # Example String

# Parse str loop
for ($i = 0, $j = 1, $l = strlen($str); $i < $l; ++$i, ++$j)
{
    if ($str{$i} == '^' && is_numeric($str{$j}))
    {
        // Save Δ Change Array Key Number & Δ Len of Replace Str;
        $ΔAKN = $str[$j]; # Δ (Change) Array Key Number;
        $ΔLen = strlen($ecma48[$ΔAKN]); # Δ (Change) Array Value Len. 
        // Remove The Formatting
        $str[$i] = NULL; # Remove ^
        $str[$j] = NULL; # Remove Int.
        // Place ECMA-48 Charaters into String.
        $str = str_inject($str, $ecma48[$ΔAKN], $i);
        // Move Str Pointers Past Δ.
        $i += $ΔLen;
        $j += $ΔLen;
        // And Increase String Size to New Length.
        $l += $ΔLen - 2; # Minus two because we removed the formatting already.
    }
}

# Print results.
echo $str;

?>
Mark Tomlin