JavaScript中使用正则表达式替换Emoji Unicode符号

14

众所周知,表情符号编码需要 3 或 4 个字节才能表示,因此在我的字符串中可能会占用 2 个符号。例如,“wew”.length = 7 我想要在文本中查找这些符号,并将其替换为依赖于其代码的值。在阅读 Stack Overflow 的帖子时,我遇到了 XRegExp 库和 unicode 插件,但是不知道如何使用它。

var str = 'wew';// \u1F601 symbol
var reg = XRegExp('[\u1F601-\u1F64F]', 'g'); //  /[ὠ1-ὤF]/g -doesn't make a lot of sense  
//var reg = XRegExp('[\uD83D\uDE01-\uD83D\uDE4F]', 'g'); //Range out of order in character class
//var reg = XRegExp('\\p{L}', 'g'); //doesn't match my symbols
console.log(XRegExp.replace(str, reg, function(match){
   return encodeURIComponent(match);// here I want to have smth like that %F0%9F%98%84 to be able to map anything I want to this value and replace to it
}));

jsfiddle

我真的不想暴力破解字符串,寻找我的范围内字符的序列。有人能帮我用正则表达式找到方法吗?

编辑 刚想到一个列举所有表情符号的想法。比暴力破解好,但仍在寻找更好的想法。

var reg = XRegExp('\uD83D\uDE01|\uD83D\uDE4F|...','g');

你为什么要匹配字节而不是码点?你使用的例子'[\u1F601-\u1F64F]'是匹配这些点的正确方式(尽管块是U+1F300-U+1F5FF)。 - 一二三
不仅仅是字节,我尝试了很多种方法,但可能做错了。那么使用这些代码点的正则表达式是什么?XRegExp('[\u1F300-\u1F5FF]','g');? - Fedor Skrynnikov
1
Javascript本身不支持超出U+FFFF的字符。在Javascript字符串中,\u1F601编码了两个字符,即U+1F60和ASCII '1'。无法在字符类中使用U+1F601 - n. m.
正则表达式/[\uD800-\uDBFF][\uDC00-\uDFFF]/g解决了我的问题。它不仅包括表情符号,还包括特殊字符。参考自https://dev59.com/tG865IYBdhLWcg3wlviq。 - Chemical Programmer
9个回答

13

\u.... 表示四位十六进制数的码点,不能多也不能少,因此只能表示 U+FFFF 以下的 Unicode 字符。超出该范围的 Unicode 字符需要以代理对形式表示。

所以需要采用某种间接方法,参见 JavaScript strings outside of the BMP

例如,你可以寻找在范围 [\uD800-\uDBFF](高代理项)内的码点,并检查字符串中下一个码点是否在范围 [\uDC00-\uDFFF] 内(如果不是,则存在严重的数据错误),将它们解释为一个 Unicode 字符,并替换为任何你想放置的内容。这看起来像是通过字符串简单循环实现,而不是使用正则表达式。


3
谢谢。但这几乎是我在编辑问题的版本中想到的。我真的想避免循环,因为每次更改字符串时都要使用它。但你激发了我使用XRegExp('[\uD800-\uDBFF][\uDC00-\uDFFF]','g')的想法。我想这对我来说已经够好了。 - Fedor Skrynnikov

10

这篇文章有点旧,但我正在研究这个问题,Bradley Momberger在此发表了一个不错的解决方案:http://airhadoken.github.io/2015/04/22/javascript-string-handling-emoji.html

他提出的正则表达式是:

/[\uD800-\uDFFF]./ // This matches emoji

这个正则表达式匹配头代理,它被表情符号使用,并且匹配跟在头代理后面的字符(假定是尾代理)。因此,所有表情符号都应该被正确匹配。

.replace(/[\uD800-\uDFFF]./g,'')

您应该能够删除所有表情符号。

编辑:找到了更好的正则表达式。上面的正则表达式会错过一些表情符号。

但是有一个Reddit帖子有一个版本,我找不到一个例外于此规则的表情符号。 Reddit在这里: https://www.reddit.com/r/tasker/comments/4vhf2f/how_to_regex_emojis_in_tasker_for_search_match_or/ 正则表达式如下:

/[\uD83C-\uDBFF\uDC00-\uDFFF]+/

为了匹配所有出现的情况,请使用 g 修饰符:
/[\uD83C-\uDBFF\uDC00-\uDFFF]+/g

第二次编辑:正如CodeToad正确指出的那样,✨没有被上面的正则表达式识别出来,因为它在dingbats块中(感谢air_hadoken)。

lodash库提供了一个优秀的Emoji正则表达式块:

(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*

在他的博客文章中,Kevin Scott很好地概述了这个正则表达式所涵盖的内容。提示:它包括装饰符。


这是我迄今为止测试过的最好的一个。虽然它缺少了这个表情符号:✨ - CodeToad
1
@CodeToad ✨("sparkles")来自dingbats块,可以在UTF-16中表示而不需要代理对。如果您想要捕获它们,您需要检查/[\u2700-\u27BF][\uFE0E-\uFE0F]?/(后一个范围是可能的变量选择器)。 - air_hadoken
已编辑为包含 dingbats 块的新 Regex,该 Regex 来自 lodash。 - Andreas Zwettler

8
也许你可以看一下这篇文章:http://crocodillon.com/blog/parsing-emoji-unicode-in-javascript\u1F601\u1F64F的表情符号Unicode,转换为JavaScript的UTF-16编码是\ud83d\ude00\ud83d\ude4f 第一个字符始终是\ud83d
因此,正则表达式如下:
/\ud83d[\ude00-\ude4f]/g

希望这可以提供一些帮助


这在2021年末很好地工作了,谢谢。 - nima

5
  1. /\ud83d[\ude00-\ude4f]/g

不包括所有表情符号,例如:: ,请查看http://getemoji.com/并尝试您的正则表达式https://regex101.com/

  1. /[\uD83C-\uDBFF\uDC00-\uDFFF]+/g

不包括所有表情符号,例如:⛑ ☕️ ☁️☄️ ☀️☃️ ⛄️ ❄️ ☹️☺️⛩⛱™️ ©️ ®️ 〰️ ➰ ➿

  1. 即使使用此正则表达式也无法删除所有表情符号...:

https://github.com/nizaroni/emoji-strip/blob/master/dist/emoji-strip.js#L79

那么,你可以说一下为什么你认为这些正则表达式不能完全删除所有奇异字符和表情符号吗?

/[\u1000-\uFFFF]+/g

2

要删除所有可能的表情符号:

new RegExp('[\u1000-\uFFFF]+', 'g');

你能解释一下为什么是-1吗? - Adrien Parrochia
1
这个正则表达式非常有用,可以删除所有异国情调的字符,包括那些来自外语的表情符号。作为一名法国开发者,我只想在网页文本中使用UTF-8字符。这个正则表达式可能会多余地删除哪些字符? - Adrien Parrochia

0

以下正则表达式模式在Java中对我有效。

"[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]"

由于Java字符串使用UTF-16编码,而表情符号的编码也在0xFFFF以上,因此这个正则表达式模式考虑代理对来识别表情符号。


0
为了好玩:不使用正则表达式删除特殊字符的解决方案
const str = "abcdefgehijkz Раз, два три! 1234567809 -ab A Z & é è Ö â                   ☺️                               ☹️                                                          -axxb-"


/********* with regExp ***********/
let startTime = new Date().getTime();
let resp = str.replace(new RegExp('[\u00FF-\uFFFF]+','g'), '');
console.log(resp);
console.log(new Date().getTime() - startTime);


/********* without regExp ***********/
startTime = new Date().getTime();
resp = Array.from(str, x => {
  let theUnicode = x.charCodeAt(0).toString(16);
  while (theUnicode.length < 4) {
    theUnicode = '0' + theUnicode;
  }
  if (theUnicode < '00ff') { 
    return x;
  }
}).join('');
console.log(resp);
console.log(new Date().getTime() - startTime);

-3

1
正确的解决方案应该处理表情符号的 _范围_,而不仅仅是一个。 - David Hariri

-3

范围在U+1F600到U+1F64F的表情符号

您可以在脚本中使用此行以Json格式发送:

text.replace(/[\u1F60-\u1F64]|[\u2702-\u27B0]|[\u1F68-\u1F6C]|[\u1F30-\u1F70]{\u2600-\u26ff]/g, "");

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