运行着一批每天自动发布新内容的静态网站,大部分时间无人值守。其中一条内部风格规则很简单:我们自己的文案中不允许出现任何emoji。
这条规则靠人工根本无法执行。一个站点每次构建会生成几百个HTML文件,emoji可能溜进导航图标、按钮标签、、RSS订阅源,甚至JSON-LD(嵌入页面中用于向搜索引擎描述页面结构的JSON格式元数据)。没人会在每次部署前把所有这些都审查一遍。</p>
![]()
所以我写了emoji-lint,一个只要发现一个emoji就立即以退出码1结束的检查工具。它位于部署前的门禁环节,这意味着一旦检查失败,当天的发布就会被中止。
这篇文章要讲的不是正则表达式本身,而是当你在真实运行环境中加入一个会失败的检查时会发生什么:你会立刻发现哪些地方规则必须豁免。
核心实现并不复杂
核心部分没什么特别之处。一个正则表达式保存了emoji的码点范围,扫描器逐行遍历每个文件,匹配到的行以JSON格式输出。
const EMOJI_RE =/[\u{1F000}-\u{1FAFF}\u{2600}-\u{27BF}\u{2B00}-\u{2BFF}\u{1F1E6}-\u{1F1FF}\u{FE0F}\u{200D}\u{2049}\u{203C}\u{2122}\u{2139}]/u;其中\u{FE0F}(变体选择符)和\u{200D}(零宽连接符)被包含在内,因为emoji并不总是单个码点。普通技术写作中使用的箭头和类似符号则被有意排除在外。如果什么都抓,检查就会被误报淹没,到那时人们就不再关注它了。
真正有意思的部分在后面
有趣的部分后来才出现。有三类内容看起来完全像违规,但绝不能当作违规处理:
- 删除其中任何一个emoji,都会破坏比风格规则更重要的东西。
先说明一个术语:这里的"掩蔽"(masking)是指用空格替换某个范围,使扫描器无法看到它。文件中的任何内容都不会被删除。
引号只有在元素带有data-quote="verbatim"属性时才被排除。
function maskVerbatimQuotes(text) {let masked = 0;const out = text.replace(VERBATIM_RE, (m, open, tag, inner, close) => {masked++;// 保留换行符,其余全部替换为空格 -> 行号保持不变return open + inner.replace(/[^\n]/g, " ") + close;return { text: out, masked };显而易见的替代方案是排除任何带有类似引用的class(如.quote)的元素。我否决了这个方案。如果仅仅一个装饰性的class就能换来豁免权,那么任何想用emoji的人只要加上这个class,规则就形同虚设。只排除那些明确声明意图的标记,才能让逃生通道保持狭窄。
inner.replace(/[^\n]/g, " ")特意保留换行符。在掩蔽后的文本中找到的行号可以直接映射回原始文件。如果压缩了文本,每个报告的行号都会偏移,这会让报告对实际修复毫无用处。
第二类情况需要不同的处理单元
以漫画标题ラブ★コン为例:★(U+2605)是官方标题的一部分。如果把它改写为ラブコン,就改变了作品本身的名称。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.