表情符号替换 - PHP

4

我需要将文本表情替换为html图像标签。我整理了以下数据:

private $smile = array(">:]", ":-)", ":)", ":o)", ":]", ":3", ":c)", ":>", "=]", "8)", "=)", ":}", ":^)");
private $laugh = array(">:D", ":-D", ":D", "8-D", "x-D", "X-D", "=-D", "=D", "=-3", "8-)");
private $sad = array(">:[", ":-(", ":(",  ":-c", ":c", ":-<", ":-[", ":[", ":{", ">.>", "<.<", ">.<");
private $wink = array(">;]", ";-)", ";)", "*-)", "*)", ";-]", ";]", ";D", ";^)");
private $tongue = array(">:P", ":-P", ":P", "X-P", "x-p", ":-p", ":p", "=p", ":-Þ", ":Þ", ":-b", ":b", "=p", "=P");
private $surprise = array(">:o", ">:O", ":-O", ":O", "°o°", "°O°", ":O", "o_O", "o.O", "8-0");
private $annoyed = array(">:\\", ">:/", ":-/", ":-.", ":\\", "=/", "=\\", ":S");
private $cry = array(":'(", ";'(");

private $t_smile = "<img class=\"smiley\" src=\"/images/emoticons/smile.png\"/>";
private $t_laugh = "<img class=\"smiley\" src=\"/images/emoticons/laugh.png\"/>";
private $t_sad = "<img class=\"smiley\" src=\"/images/emoticons/sad.png\"/>";
private $t_wink = "<img class=\"smiley\" src=\"/images/emoticons/wink.png\"/>";
private $t_tongue = "<img class=\"smiley\" src=\"/images/emoticons/tongue.png\"/>";
private $t_surprise = "<img class=\"smiley\" src=\"/images/emoticons/surprise.png\"/>";
private $t_annoyed = "<img class=\"smiley\" src=\"/images/emoticons/annoyed.png\"/>";
private $t_cry = "<img class=\"smiley\" src=\"/images/emoticons/cry.png\"/>"

我目前只是举个例子:

$str = str_replace($this->laugh, $this->t_laugh, $str);

对于每个组,它都能正常工作,但我需要替换仅在单词周围没有字母或其他数字的情况下发生。换句话说,我需要编译一个包含每个表情符号数组的正则表达式,以便我可以使用preg_replace而不是str_replace。有没有一种简单的方法可以做到这一点,而不是硬编码正则表达式并转义所有必要的字符?
编辑:
此外,我需要匹配和替换出现在字符串开头和结尾的表情符号,因此简单的填充空格技术不足以满足需求。
编辑2:
我按照Mark的示例使用preg_quote从数组中预编译了正则表达式,如下所示:
private $smile = "#(^|\W)(\>\:\]|\:-\)|\:\)|\:o\)|\:\]|\:3|\:c\)|\:\>|\=\]|8\)|\=\)|\:\}|\:\^\))($|\W)#";
private $laugh = "#(^|\W)(\>\:D|\:-D|\:D|8-D|x-D|X-D|\=-D|\=D|\=-3|8-\)|xD|XD|8D|\=3)($|\W)#";
private $sad = "#(^|\W)(\>\:\[|\:-\(|\:\(|\:-c|\:c|\:-\<|\:-\[|\:\[|\:\{|\>\.\>|\<\.\<|\>\.\<)($|\W)#";
private $wink = "#(^|\W)(\>;\]|;-\)|;\)|\*-\)|\*\)|;-\]|;\]|;D|;\^\))($|\W)#";
private $tongue = "#(^|\W)(\>\:P|\:-P|\:P|X-P|x-p|\:-p|\:p|\=p|\:-Þ|\:Þ|\:-b|\:b|\=p|\=P|xp|XP|xP|Xp)($|\W)#";
private $surprise = "#(^|\W)(\>\:o|\>\:O|\:-O|\:O|°o°|°O°|\:O|o_O|o\.O|8-0)($|\W)#";
private $annoyed = "#(^|\W)(\>\:\\|\>\:/|\:-/|\:-\.|\:\\|\=/|\=\\|\:S|\:\/)($|\W)#";
private $cry = "#(^|\W)(\:'\(|;'\()($|\W)#";

与 preg_replace 完美配合!


4
对于此事,您应该使用关联数组。 - Dhaivat Pandya
你能否在数组中的值两侧添加一个空格并继续使用 str_replace 吗? - Frank
3个回答

5

如果您想使用正则表达式:

$pat = '#(^|\W)'.preg_quote($this->laugh,'#').'($|\W)#';
$str = str_replace($pat, $this->t_laugh, $str);

这基本上意味着表情符号可以位于字符串的开头或在非单词字符之前,必须跟随字符串的结尾或另一个非单词字符。如果您的表情符号包含任何特殊的正则表达式字符,则需要使用 preg_quote。另外,更好的格式可能是:
$emoticons = array(
    'smile' => array('<img src...', array('>:]',':-)',...),
    'laugh' => array('<img src....', array(...)),
    ...
)

然后您可以循环遍历所有内容。


更新

应该使用负向先行断言来匹配并排的表情符号。这样它就不会尝试匹配周围的空格了。

<?php
$smile = array(">:]", ":-)", ":)", ":o)", ":]", ":3", ":c)", ":>", "=]", "8)", "=)", ":}", ":^)");
$laugh = array(">:D", ":-D", ":D", "8-D", "x-D", "X-D", "=-D", "=D", "=-3", "8-)");
$sad = array(">:[", ":-(", ":(",  ":-c", ":c", ":-<", ":-[", ":[", ":{", ">.>", "<.<", ">.<");
$wink = array(">;]", ";-)", ";)", "*-)", "*)", ";-]", ";]", ";D", ";^)");
$tongue = array(">:P", ":-P", ":P", "X-P", "x-p", ":-p", ":p", "=p", ":-Ã", ":Ã", ":-b", ":b", "=p", "=P");
$surprise = array(">:o", ">:O", ":-O", ":O", "°o°", "°O°", ":O", "o_O", "o.O", "8-0");
$annoyed = array(">:\\", ">:/", ":-/", ":-.", ":\\", "=/", "=\\", ":S");
$cry = array(":'(", ";'(");

$ary = array_merge($smile, $laugh, $sad, $wink, $tongue,$surprise,$annoyed,$cry);

foreach ($ary as $a)
{
        $quoted[] = preg_quote($a, '#');
}

$regex = implode('|', $quoted);


$full = '#(?!<\w)(' . $regex .')(?!\w)#';
echo $full.PHP_EOL;
$str = "Testing :) emoticons :D :(";

preg_match_all($full, $str, $matches);
print_r($matches[0]);

此外,在编写正则表达式模式时,请尽可能使用单引号,因为双引号允许转义序列,而单引号不会解释转义序列。也就是说,当使用双引号时,有时需要加倍斜杠。


如果是True,那么它只会逻辑上OR每个模式。不错的解决方案。我建议将其添加到您的答案中。 - Josh
@dscer:呃...我不太确定它出了什么问题。如果它前面没有立即出现一个图标,它是可以正常工作的:http://ideone.com/Vl8Kf - mpen
@Mark:很奇怪...尽管所有表情符号都被指定了,但在这个正则表达式中它不起作用:http://ideone.com/clone/ETGAO - dscer
@dscer: 在 :D 后面加上 "x" 就可以找到最后一个了:http://ideone.com/fvBoH。我在想是不是 preg_match_all 不喜欢 si...,不,我刚刚想通了。:D 和 :( 都匹配它们之间的空格,而且不能重叠匹配。我认为我们可以用负向先行断言来找到这个问题... - mpen
显示剩余2条评论

0

可能有一个类似格式化循环的东西

for($i=0;$i<count($smiles);++$i){
   $smiles[$i]="~\s".$smiles[$i]."\s~";
}

然后只需要将其插入 preg_replace($smiles,$t_smiles,$text) 中即可。


0

以下类似的内容可能是您正在寻找的:

function toRegex(array $emotes) {
    foreach ($emotes as &$emote)
        $emote = preg_quote($emote, "/");
    return "/\b" . implode($emotes, "\b|\b") . "\b/";
}

$imaged = preg_replace(toRegex($smiles), $t_smiles);

此外,正如马克提到的那样,最好使用一个包含所有表情符号的巨大数组,而不是一百个需要手动处理的小变量。

单词边界在这里不起作用。我相信一侧必须有一个单词字符,另一侧必须有一个非单词字符。笑脸中的“:”和“)”不是单词字符,因此\b在像“:)”这样的字符串中不会匹配任何内容(两侧都有空格)。实际上,它会匹配x:),这正好与我们想要的相反。 - mpen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接