Mirc控制代码到html,通过php

时间:2012-04-26 08:05:49

标签: php html regex preg-replace mirc

我之前已经意识到这已经在这个论坛上被提出过了,但是建议的解决方案对我来说并不可靠。

到目前为止,我已经为此工作了一个星期或更长时间,我一直待到凌晨3点才开始工作......但我离题了,让我来看看手头的问题:

对于那些不知道的人,mirc使用ascii控制代码来控制字符颜色,下划线,粗细和斜体。颜色的ascii代码为3,粗体2,下划线1F,斜体1D和反向(黑色背景上的白色文本),16。

作为这个数据的形式的一个例子,我们有(在正则表达式,因为这些字符不会打印):

\x034this text is red\x033this text is green\x03 \x02bold text\x02
\x034,3this text is red with a green background\x03

Et一等等。

以下是我试图修改供我自己使用的两个函数,但返回的结果不可靠。在我进入代码之前,要具体说“不可靠”,有时代码会解析,有时候文本中仍然会有控制代码,我无法弄清楚原因。无论如何;

function mirc2html($x) {
    $c = array("FFF","000","00007F","009000","FF0000","7F0000","9F009F","FF7F00","FFFF00","00F800","00908F","00FFFF","0000FF","FF00FF","7F7F7F","CFD0CF");
    $x = preg_replace("/\x02(.*?)((?=\x02)\x02|$)/", "<b>$1</b>", $x);
    $x = preg_replace("/\x1F(.*?)((?=\x1F)\x1F|$)/", "<u>$1</u>", $x);
    $x = preg_replace("/\x1D(.*?)((?=\x1D)\x1D|$)/", "<i>$1</i>", $x);
    $x = preg_replace("/\x03(\d\d?),(\d\d?)(.*?)(?(?=\x03)|$)/e", "'</span><span style=\"color: #'.\$c[$1].'; background-color: #'.\$c[$2].';\">$3</span>'", $x);
    $x = preg_replace("/\x03(\d\d?)(.*?)(?(?=\x03)|$)/e", "'</span><span style=\"color: #'.\$c[$1].';\">$2</span>'", $x);
    //$x = preg_replace("/(\x0F|\x03)(.*?)/", "<span style=\"color: #000; background-color: #FFF;\">$2</span>", $x);
    //$x = preg_replace("/\x16(.*?)/", "<span style=\"color: #FFF; background-color: #000;\">$1</span>", $x);
    //$x = preg_replace("/\<\/span\>/","",$x,1);
    //$x = preg_replace("/(\<\/span\>){2}/","</span>",$x);
    return $x;
}

function color_rep($matches) {
    $matches[2] = ltrim($matches[2], "0");
    $bindings = array(0=>'white',1=>'black',2=>'blue',3=>'green',4=>'red',5=>'brown',6=>'purple',7=>'orange',8=>'yellow',9=>'lightgreen',10=>'#00908F',
        11=>'lightblue',12=>'blue',13=>'pink',14=>'grey',15=>'lightgrey');
    $preg = preg_match_all('/(\d\d?),(\d\d?)/',$matches[2], $col_arr);
    //print_r($col_arr);
    $fg = isset($bindings[$matches[2]]) ? $bindings[$matches[2]] : 'transparent';
    if ($preg == 1) {
        $fg = $bindings[$col_arr[1][0]];
        $bg = $bindings[$col_arr[2][0]];
    }
    else {
        $bg = 'transparent';
    }


    return '<span style="color: '.$fg.'; background: '.$bg.';">'.$matches[3].'</span>';
}

并且,如果相关,则调用代码:

$logln = preg_replace_callback("/(\x03)(\d\d?,\d\d?|\d\d?)(\s?.*?)(?(?=\x03)|$)/","color_rep",$logln);

来源:FirstSecond

我当然也试图查看各种基于php / ajax的irc客户端所做的方法,并且那里没有任何成功。至于做这个mirc端,我也看了一下,虽然结果比php更可靠,但发送到服务器的数据呈指数级增长到套接字在上传时超时的程度,所以它不是一个可行的选择。

与往常一样,对此事的任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:3)

您应该将问题分开,例如使用标记器。标记生成器将扫描输入字符串并将特殊部分转换为命名标记,因此脚本的其余部分可以识别它们。用法示例:

$mirc = "\x034this text is red\x033this text is green\x03 \x02bold text\x02
\x034,3this text is red with a green background\x03";

$tokenizer = new Tokenizer($mirc);

while(list($token, $data) = $tokenizer->getNext())
{
    switch($token)
    {
        case 'color-fgbg':
            printf('<%s:%d,%d>', $token, $data[1], $data[2]);
            break;

        case 'color-fg':
            printf('<%s:%d>', $token, $data[1]);
            break;

        case 'color-reset':
        case 'style-bold';
            printf('<%s>', $token);
            break;

        case 'catch-all':
            echo $data[0];
            break;

        default:
            throw new Exception(sprintf('Unknown token <%s>.', $token));
    }
}

这还没有多少,但是在输出演示时会识别出有趣的部分及其(子)值:

<color-fg:4>this text is red<color-fg:3>this text is green<color-reset> <style-bold>bold text<style-bold>
<color-fgbg:4,3>this text is red with a green background<color-reset>

您可以相对轻松地修改上面的循环并处理打开/关闭颜色和粗体等字体变体标记等状态。

标记器本身定义了一组标记,它们试图在某个偏移处(从字符串的开头开始)一个接一个地找到它们。标记由正则表达式定义:

/**
 * regular expression based tokenizer,
 * first token wins.
 */
class Tokenizer
{
    private $subject;
    private $offset = 0;
    private $tokens = array(
        'color-fgbg'  => '\x03(\d{1,2}),(\d{1,2})',
        'color-fg'    => '\x03(\d{1,2})',
        'color-reset' => '\x03',
        'style-bold'  => '\x02',
        'catch-all' => '.|\n',
    );
    public function __construct($subject)
    {
        $this->subject = (string) $subject;
    }
    ...

正如这个私有数组所示,简单的正则表达式,他们得到一个带有键的名称。这是上面switch语句中使用的名称。

next()函数将在当前偏移处查找标记,如果找到,将提前偏移并返回标记incl。所有小组匹配。由于涉及偏移,更简单的$matches数组被简化(偏移被移除),因为主程序通常不需要知道偏移。

这里的原则很简单:第一种模式获胜。因此,您需要将最匹配的模式(在字符串长度方面)置于顶部以使其正常工作。在您的情况下,最大的一个是前景色和背景色的标记<color-fgbg>

如果找不到令牌,则返回NULL,所以这里next()函数:

...
/**
 * @return array|null
 */
public function getNext()
{
    if ($this->offset >= strlen($this->subject))
        return NULL;

    foreach($this->tokens as $name => $token)
    {
        if (FALSE === $r = preg_match("~$token~", $this->subject, $matches, PREG_OFFSET_CAPTURE, $this->offset))
            throw new RuntimeException('Pattern for token %s failed (regex error).', $name);
        if ($r === 0)
            continue;
        if (!isset($matches[0])) {
            var_dump(substr($this->subject, $this->offset));
            $c = 1;
        }
        if ($matches[0][1] !== $this->offset)
            continue;
        $data = array();
        foreach($matches as $match)
        {
            list($data[]) = $match;
        }

        $this->offset += strlen($data[0]);
        return array($name, $data);
    }
    return NULL;
}
...

因此,字符串的标记化现在被封装到Tokenizer类中,并且您可以在应用程序的其他部分内自行解析令牌。这应该让你更容易改变样式的方式(HTML输出,基于CSS的HTML输出或不同的bbcode或markdown),以及未来对新代码的支持。如果缺少某些东西,你可以更容易地解决问题,因为它是一个不可识别的代码或转换中缺少的东西。

完整示例为gist:Tokenizer Example of Mirc Color and Style (bold) Codes.

相关资源: