转换图片表情为文字
Frownies 是对一个玩笑的回应。Greasemonkey 邮件列表有人宣称他们开发了一个用户脚本,可以把 ASCII “表情符号” 比如 :-) 转换为与它们相同含义的图片。其他人答复道,想知道要完成逆向转换要花多久时间:转换图片表情为文本。
为了创纪录,我花了大约20分钟。大部分时间是花在研究已发布的自动转换图片表情的软件上了,然后编写了详尽的转换表。
这个脚本倚赖于能自动生成表情图片的大多数软件有如下特征:这些软件会把相同含义的文字表情符号放在 <img> 元素的 alt 属性里。所以,这个脚本实际上所做的是:如果 ALT 文本匹配预定义的常量列表中的某一条,就用图片的 ALT 文本来替换图片。
例 5.6.
frownies.user.js
// ==UserScript==
// @name Frownies
// @namespace http://diveintogreasemonkey.org/download/
// @description convert graphical smilies to their text equivalents
// @include *
// ==/UserScript==
var smilies, images, img, replacement;
smilies = [":)", ":-)" ":-(", ":(", ";-)", ";)", ":-D", ":D", ":-/",
":/", ":X", ":-X", ":\">", ":P", ":-P", ":O", ":-O", "X-(",
"X(", ":->", ":>", "B-)", "B)", ">:)", ":((", ":(((", ":-((",
":))", ":-))", ":-|", ":|", "O:-)", "O:)", ":-B", ":B", "=;",
"I)", "I-)", "|-)", "|)", ":-&", ":&", ":-$", ":$", "[-(", ":O)",
":@)", "3:-O", ":(|)", "@};-", "**==", "(~~)", "*-:)", "8-X",
"8X", "=:)", "<):)", ";;)", ":*", ":-*", ":S", ":-S", "/:)",
"/:-)", "8-|", "8|", "8-}", "8}", "(:|", "=P~", ":-?", ":?",
"#-O", "#O", "=D>", "~:>", "%%-", "~O)", ":-L", ":L", "[-O<",
"[O<", "@-)", "@)", "$-)", "$)", ">-)", ":-\"", ":^O", "B-(",
"B(", ":)>-", "[-X", "[X", "\\:D/", ">:D<", "(%)", "=((", "#:-S",
"#:S", "=))", "L-)", "L)", "<:-P", "<:P", ":-SS", ":SS", ":-W",
":W", ":-<", ":<", ">:P", ">:-P", ">:/", ";))", ":-@", "^:)^",
":-J", "(*)", ":GRIN:", ":-)", ":SMILE:", ":SAD:", ":EEK:",
":SHOCK:", ":???:", "8)", "8-)", ":COOL:", ":LOL:", ":MAD:",
":RAZZ:", ":OOPS:", ":CRY:", ":EVIL:", ":TWISTED:", ":ROLL:",
":WINK:", ":!:", ":?:", ":IDEA:", ":ARROW:", ":NEUTRAL:",
":MRGREEN:"];
images = document.evaluate(
'//img[@alt]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
for (var i = 0; i < images.snapshotLength; i++) {
img = images.snapshotItem(i);
alt = img.alt.toUpperCase();
for (var j in smilies) {
if (alt == smilies[j]) {
replacement = document.createTextNode(alt);
img.parentNode.replaceChild(replacement, img);
}
}
}这段代码分为四个步骤:
- 定义表情符号的列表(文本格式)。
- 找出页面中所有含有
alt属性的图片。 - 对每一幅图像,检测它的 ALT 文本是否与列表中的某个 ASCII 表情符号匹配。
- 如果匹配,就替换
<img>元素为包含 ASCII 表情的文本节点。
第一步简单的定义了一个列表,用 Javascript 的 [ ] 语法。
smilies = [":)", ":-)" ":-(", ":(", ";-)", ";)", ":-D", ":D", ":-/",
":/", ":X", ":-X", ":\">", ":P", ":-P", ":O", ":-O", "X-(",
"X(", ":->", ":>", "B-)", "B)", ">:)", ":((", ":(((", ":-((",
":))", ":-))", ":-|", ":|", "O:-)", "O:)", ":-B", ":B", "=;",
"I)", "I-)", "|-)", "|)", ":-&", ":&", ":-$", ":$", "[-(", ":O)",
":@)", "3:-O", ":(|)", "@};-", "**==", "(~~)", "*-:)", "8-X",
"8X", "=:)", "<):)", ";;)", ":*", ":-*", ":S", ":-S", "/:)",
"/:-)", "8-|", "8|", "8-}", "8}", "(:|", "=P~", ":-?", ":?",
"#-O", "#O", "=D>", "~:>", "%%-", "~O)", ":-L", ":L", "[-O<",
"[O<", "@-)", "@)", "$-)", "$)", ">-)", ":-\"", ":^O", "B-(",
"B(", ":)>-", "[-X", "[X", "\\:D/", ">:D<", "(%)", "=((", "#:-S",
"#:S", "=))", "L-)", "L)", "<:-P", "<:P", ":-SS", ":SS", ":-W",
":W", ":-<", ":<", ">:P", ">:-P", ">:/", ";))", ":-@", "^:)^",
":-J", "(*)", ":GRIN:", ":-)", ":SMILE:", ":SAD:", ":EEK:",
":SHOCK:", ":???:", "8)", "8-)", ":COOL:", ":LOL:", ":MAD:",
":RAZZ:", ":OOPS:", ":CRY:", ":EVIL:", ":TWISTED:", ":ROLL:",
":WINK:", ":!:", ":?:", ":IDEA:", ":ARROW:", ":NEUTRAL:",
":MRGREEN:"];接下来,我在页面中使用 XPath 查询语句搜索所有的含有 alt 属性的 <img> 元素。有关 XPath 查询语句的更多信息,请阅读操作所有有特定属性的元素。
images = document.evaluate( '//img[@alt]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
第三步,遍历所有的 <img>元素,检验 alt 属性是否与我们定义的表情符号匹配。由于一些表情符号含有字母,我用toUpperCase()方法在比较前把 alt 属性转换为大写。
for (var i = 0; i < images.snapshotLength; i++) {
img = images.snapshotItem(i);
alt = img.alt.toUpperCase())
for (var j in smilies) {
if (alt == smilies[j]) {
// ...
}
}
}最后,我创建了一个包含文字表情符号的新文本节点,然后用它替换掉已有的 <img> 元素。更多的信息,请阅读替换元素为新内容。
replacement = document.createTextNode(alt); img.parentNode.replaceChild(replacement, img);