我之前已经意识到这已经在这个论坛上被提出过了,但是建议的解决方案对我来说并不可靠。
到目前为止,我已经为此工作了一个星期或更长时间,我一直待到凌晨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);
我当然也试图查看各种基于php / ajax的irc客户端所做的方法,并且那里没有任何成功。至于做这个mirc端,我也看了一下,虽然结果比php更可靠,但发送到服务器的数据呈指数级增长到套接字在上传时超时的程度,所以它不是一个可行的选择。
与往常一样,对此事的任何帮助都将不胜感激。
答案 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.
相关资源: