正则表达式删除除表情符号以外的所有非字母数字字符

时间:2015-08-13 14:12:40

标签: php regex preg-replace

我需要删除除空格和允许表情符号之外的所有非字母数字字符。

允许的表情符号为:):(:P等(最受欢迎)。

我有一个字符串:

$string = 'Hi! Glad # to _ see : you :)';

所以我需要处理这个字符串并获得以下内容:

$string = 'Hi Glad to see  you :)';

另外请注意表情符号可以包含空格

e.g。

:)而不是:)

:P 而不是:P

有没有人有这样做的功能?

如果有人帮我,那就太棒了:)。

更新

非常感谢你的帮助。

buckley 提供了现成的解决方案,

但是如果字符串包含带空格的表情符号

e.g。 嗨!很高兴#到_见:你:)

结果等于很高兴见到你

因为你看到表情符号:)被切断了。

5 个答案:

答案 0 :(得分:3)

我不会"说" php;)但这在JS中做到了。也许你可以转换它。

var sIn = 'Hi! Glad # to _ see : you :)',
    sOut;

sOut = sIn.match(/([\w\s]|: ?\)|: ?\(|: ?P)*/g).join('');

它在你的尝试中起作用 - 它发现所有"合法"字符/组合并将它们连接在一起。

此致

编辑:更新了正则表达式以处理表情符号中的可选空格(如前面所述)。

答案 1 :(得分:2)

哈!这个很有意思

替换

wxMBConvUTF8

什么都没有

这个想法是你用同样的正则表达式将非法字符夹在一边作为负面看起来,而将其作为负面看后面。

结果中会有连续的空格。这是正则表达式在1次扫描AFAIK中无法做到的事情,因为它不能同时查看多个匹配。

要删除连续的空格,您可以将(?!(:\)|:\(|:P))[^a-zA-Z0-9 ](?<!(:\)|:\(|:P)) 替换为\s+(空格)

答案 2 :(得分:2)

这是一个更新的答案,符合表情符号可以包含空格的新要求

替换

((:\))|(:\()|(:P)|(: \))|: P)|[^0-9a-zA-Z\r\n ]

使用

$1

在自由间隔模式下格式化,这变为

(?x)
(
  (?::\))|
  (?::\()|
  (?::P)|
  (?::\ \))|
  :\ P
)|
[^0-9a-zA-Z\r\n ]

在PHP中

$result = preg_replace('/((:\))|(:\()|(:P)|(: \))|: P)|[^0-9a-zA-Z\r\n ]/', '$1', $subject);

我们的想法是,我们使用包含多个字符的表情符号启动正则表达式,这些表情符号可以包含非法字符。

此组被捕获,后来用作替换$ 1

然后,在交替之后,我们使用我们否定的字符白名单,以便匹配,但在替换模式中不会提及。

所有不匹配的东西(我们的白名单)将按照惯例在结果中重复。

关于不存在的事情是在列出可能妨碍性能的表情符号时有很多分组。为了防止这种情况,我们可以使正则表达式更加冗长:

 ((?::\))|(?::\()|(?::P)|(?:: \))|: P)|[^0-9a-zA-Z\r\n ]

多个连续的空格仍然存在,并且无法在1次扫描AFAIK中解决。

答案 3 :(得分:1)

这是一个字符串格式化程序,可以完成这项工作,假设表情符号通常是2个字符长:

<?php

class StringFormatter
{
  private $blacklist;
  private $whitelist;

  public function __construct(array $blacklist, array $whitelist)
  {
    $this->blacklist = $blacklist;
    $this->whitelist = $whitelist;
  }

  public function format($str)
  {
    $strLen = strlen($str);

    $result = '';
    $counter = 0;
    while ($counter < $strLen) {
      // get a character from the string
      $char = substr($str, $counter, 1);

      // if not blacklisted, allow it in the result
      if (!in_array($char, $this->blacklist)) {
        $result .= $char;
        $counter++;
        continue;
      }

      // if we reached the last letter, break out of the loop
      if ($counter >= $strLen - 1) {
        break;
      }

      // we assume all whitelisted entries have same length (e.g. 2
      // for emoticons)
      if (in_array(substr($str, $counter, 2), $this->whitelist)) {
        $result .= substr($str, $counter, 2);
        $counter += 2;
      } else {
        $counter++;
      }
    }

    return $result;
  }
}

// example usage
// $whitelist is not the entire whitelist, actually it's the exceptions
// to the blacklist, so more complext strings including blacklisted  characters that should be allowed
$formatter = new StringFormatter(['#', '_', ':', '!'], [':)', ':(']);
echo $formatter->format('Hi! Glad # to _ see : you :)');

上面的代码可以进一步重构为更清晰,但你得到了图片。

答案 4 :(得分:1)

我会使用这个正则表达式,

(?i)(:\s*[)p(])(*SKIP)(*FAIL)|[^a-z0-9 ]

演示:https://regex101.com/r/nW6iL3/2

PHP用法:

$string = ':     ) instead of :)

or

:     P instead of :P

Hi! Glad # to _ see : you :)';

echo preg_replace('~(?i)(:\s*[)p(])(*SKIP)(*FAIL)|[^a-z0-9 ]~', '', $string);

输出:

  

:)而不是:)或:P而不是:PHi很高兴见到你:)

演示:https://eval.in/416394

如果表情符号的结束部分发生变化,或者您有其他人,则可以将其添加到此角色类[)p(]中。

您也可以通过将:更改为角色类来改变眼睛,这样就可以

(?i)([:;]\s*[)p(])(*SKIP)(*FAIL)|[^a-z0-9 ] 

如果你还想允许眨眼的脸(我认为分号是眨眼)..

<强>更新

一点一点解释......

(?i) =使正则表达式不区分大小写

: =寻找眼睛(冒号)

\s* =搜索零或更多(*是前面字符的0或更多)空白字符(\h在这里可能更好,\s包括新行和制表符)

[)p(] =这是一个允许其中任何字符出现的字符类。因此,此处允许)p(

(*SKIP)(*FAIL) =如果我们发现以前的正则表达式忽略它,请访问www.rexegg.com/regex-best-trick.html。

| =或

[^a-z0-9 ] - 一个否定的字符类,表示此列表中没有的任何字符都可以找到。

regex101还有关于正则表达式的文档。