Create "NotEmoji" rule

The data in this commit has been gathered, scrapped, organized and
treated based on the Emoji Unicode V11 specification [1].

[1]: https://unicode.org/Public/emoji/11.0/emoji-test.txt

Co-authored-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Mazen Touati 2019-01-27 01:14:47 +01:00 committed by Henrique Moody
parent ffec95acda
commit 9c7550aa43
No known key found for this signature in database
GPG key ID: 221E9281655813A6
10 changed files with 357 additions and 0 deletions

View file

@ -189,6 +189,7 @@
- [Cpf](rules/Cpf.md)
- [Domain](rules/Domain.md)
- [Email](rules/Email.md)
- [Emoji](rules/Emoji.md)
- [HexRgbColor](rules/HexRgbColor.md)
- [Imei](rules/Imei.md)
- [Ip](rules/Ip.md)

View file

@ -43,6 +43,7 @@ See also:
- [Digit](Digit.md)
- [Lowercase](Lowercase.md)
- [NoWhitespace](NoWhitespace.md)
- [NotEmoji](NotEmoji.md)
- [Regex](Regex.md)
- [StringType](StringType.md)
- [StringVal](StringVal.md)

View file

@ -37,6 +37,7 @@ See also:
- [Digit](Digit.md)
- [Lowercase](Lowercase.md)
- [NoWhitespace](NoWhitespace.md)
- [NotEmoji](NotEmoji.md)
- [Regex](Regex.md)
- [Uppercase](Uppercase.md)
- [Vowel](Vowel.md)

View file

@ -32,6 +32,7 @@ See also:
- [Infinite](Infinite.md)
- [IntType](IntType.md)
- [IntVal](IntVal.md)
- [NotEmoji](NotEmoji.md)
- [NumericVal](NumericVal.md)
- [Regex](Regex.md)
- [Uuid](Uuid.md)

36
docs/rules/NotEmoji.md Normal file
View file

@ -0,0 +1,36 @@
# NotEmoji
- `v::notEmoji()`
Validates if the input does not contain an emoji.
```php
v::notEmoji()->validate('Hello World, without emoji'); // true
v::notEmoji()->validate('🍕'); // false
v::notEmoji()->validate('🎈'); // false
v::notEmoji()->validate('⚡'); // false
v::notEmoji()->validate('this is a spark ⚡'); // false
v::notEmoji()->validate('🌊🌊🌊🌊🌊🏄🌊🌊🌊🏖🌴'); // false
```
Please consider that the performance of this validator is linear which
means the longer the text the longer it takes to perform the check.
However, the validator will break the execution as soon as it finds the
first emoji or until it checks the whole text.
*Note: this validator will check the Emoji as they are defined in
Unicode V11 check the following link for more details
[Unicode v11](https://unicode.org/emoji/charts/full-emoji-list.html)*
## Changelog
Version | Description
--------|-------------
2.0.0 | Created
***
See also:
- [Alnum](Alnum.md)
- [Alpha](Alpha.md)
- [Digit](Digit.md)

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
/**
* @author Mazen Touati <mazen_touati@hotmail.com>
*/
final class NotEmojiException extends ValidationException
{
/**
* {@inheritdoc}
*/
public static $defaultTemplates = [
self::MODE_DEFAULT => [
self::STANDARD => '{{name}} must not contain an Emoji',
],
self::MODE_NEGATIVE => [
self::STANDARD => '{{name}} must contain an Emoji',
],
];
}

167
library/Rules/NotEmoji.php Normal file
View file

@ -0,0 +1,167 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Respect\Validation\Rules;
use function implode;
use function is_string;
use function preg_match;
/**
* Validates if the input does not contain an emoji.
*
* @author Mazen Touati <mazen_touati@hotmail.com>
*/
final class NotEmoji extends AbstractRule
{
private const GROUPS = [
'[\x{1F385}-\x{1F9E6}]',
'[\x{1F331}-\x{1F9A2}]',
'[\x{1F32D}-\x{1F9C2}]',
'[\x{1F300}-\x{1F9F3}]',
'[\x{1F004}-\x{1F9FF}]',
'[\x{1F399}-\x{1F9FE}]',
'[\x{1F170}-\x{1F6D0}]',
'[\x{1F38C}-\x{1F6A9}]',
'[\x{261D}]',
'[\x{2620}]',
'[\x{2639}-\x{263A}]',
'[\x{26D1}]',
'[\x{26F7}-\x{26F9}]',
'[\x{270A}-\x{270D}]',
'[\x{2763}-\x{2764}]',
'[\x{2618}]',
'[\x{2615}]',
'[\x{231A}-\x{231B}]',
'[\x{23F0}-\x{23F3}]',
'[\x{2600}-\x{2604}]',
'[\x{2614}]',
'[\x{2668}]',
'[\x{2693}]',
'[\x{26A1}]',
'[\x{26C4}-\x{26C5}]',
'[\x{26C8}]',
'[\x{26E9}-\x{26EA}]',
'[\x{26F0}-\x{26F5}]',
'[\x{26FA}]',
'[\x{26FD}]',
'[\x{2708}]',
'[\x{2744}]',
'[\x{2B50}]',
'[\x{265F}-\x{2660}]',
'[\x{2663}-\x{2666}]',
'[\x{26BD}-\x{26BE}]',
'[\x{26F3}]',
'[\x{26F8}]',
'[\x{2728}]',
'[\x{2328}]',
'[\x{260E}]',
'[\x{2692}-\x{2699}]',
'[\x{26B0}-\x{26B1}]',
'[\x{26CF}]',
'[\x{26D3}]',
'[\x{2702}]',
'[\x{2709}]',
'[\x{270F}]',
'[\x{2712}]',
'[\x{00A9}]',
'[\x{00AE}]',
'[\x{203C}]',
'[\x{2049}]',
'[\x{2122}]',
'[\x{2139}]',
'[\x{2194}-\x{2199}]',
'[\x{21A9}-\x{21AA}]',
'[\x{23CF}]',
'[\x{23EA}-\x{23EF}]',
'[\x{23F8}-\x{23FA}]',
'[\x{24C2}]',
'[\x{25AA}-\x{25AB}]',
'[\x{25B6}]',
'[\x{25C0}]',
'[\x{25FB}-\x{25FE}]',
'[\x{2611}]',
'[\x{2622}-\x{2623}]',
'[\x{2626}]',
'[\x{262A}]',
'[\x{262E}-\x{262F}]',
'[\x{2638}]',
'[\x{2640}-\x{2642}]',
'[\x{2648}-\x{2653}]',
'[\x{267B}]',
'[\x{267E}-\x{267F}]',
'[\x{2695}]',
'[\x{23E9}]',
'[\x{269B}-\x{269C}]',
'[\x{26A0}]',
'[\x{26AA}-\x{26AB}]',
'[\x{26CE}]',
'[\x{26D4}]',
'[\x{2705}]',
'[\x{2714}-\x{2716}]',
'[\x{271D}]',
'[\x{2721}]',
'[\x{2733}-\x{2734}]',
'[\x{2747}]',
'[\x{274C}-\x{274E}]',
'[\x{2753}-\x{2757}]',
'[\x{2795}-\x{2797}]',
'[\x{27A1}]',
'[\x{27B0}]',
'[\x{27BF}]',
'[\x{2934}-\x{2935}]',
'[\x{2B05}-\x{2B07}]',
'[\x{2B1B}-\x{2B1C}]',
'[\x{2B55}]',
'[\x{3030}]',
'[\x{303D}]',
'[\x{3297}-\x{3299}]',
'[\x{1F1E6}-\x{1F1FF}]',
'\x{0023}\x{20E3}',
'\x{0023}\x{FE0F}\x{20E3}',
'\x{002A}\x{20E3}',
'\x{002A}\x{FE0F}\x{20E3}',
'\x{0030}\x{20E3}',
'\x{0030}\x{FE0F}\x{20E3}',
'\x{0031}\x{20E3}',
'\x{0031}\x{FE0F}\x{20E3}',
'\x{0032}\x{20E3}',
'\x{0032}\x{FE0F}\x{20E3}',
'\x{0033}\x{20E3}',
'\x{0033}\x{FE0F}\x{20E3}',
'\x{0034}\x{20E3}',
'\x{0034}\x{FE0F}\x{20E3}',
'\x{0035}\x{20E3}',
'\x{0035}\x{FE0F}\x{20E3}',
'\x{0036}\x{20E3}',
'\x{0036}\x{FE0F}\x{20E3}',
'\x{0037}\x{20E3}',
'\x{0037}\x{FE0F}\x{20E3}',
'\x{0038}\x{20E3}',
'\x{0038}\x{FE0F}\x{20E3}',
'\x{0039}\x{20E3}',
'\x{0039}\x{FE0F}\x{20E3}',
];
/**
* {@inheritdoc}
*/
public function validate($input): bool
{
if (!is_string($input)) {
return false;
}
return 0 === preg_match('/'.implode('|', self::GROUPS).'/mu', $input);
}
}

View file

@ -115,6 +115,7 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
* @method static Validator noneOf(Validatable ...$rule)
* @method static Validator not(Validatable $rule)
* @method static Validator notBlank()
* @method static Validator notEmoji()
* @method static Validator notEmpty()
* @method static Validator notOptional()
* @method static Validator noWhitespace()

View file

@ -0,0 +1,39 @@
--CREDITS--
Mazen Touati <mazen_touati@hotmail.com>
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Exceptions\NotEmojiException;
use Respect\Validation\Validator as v;
try {
v::notEmoji()->check('🍕');
} catch (NotEmojiException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::not(v::notEmoji())->check('AB');
} catch (NotEmojiException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::notEmoji()->assert('🏄');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::not(v::notEmoji())->assert('YZ');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
?>
--EXPECT--
"🍕" must not contain an Emoji
"AB" must contain an Emoji
- "🏄" must not contain an Emoji
- "YZ" must contain an Emoji

View file

@ -0,0 +1,78 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Respect\Validation\Rules;
use Respect\Validation\Test\RuleTestCase;
use stdClass;
/**
* @group rule
*
* @covers \Respect\Validation\Rules\NotEmoji
*
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Mazen Touati <mazen_touati@hotmail.com>
*/
final class NotEmojiTest extends RuleTestCase
{
/**
* {@inheritdoc}
*/
public function providerForValidInput(): array
{
$sut = new NotEmoji();
return [
'Numbers' => [$sut, '0123456789'],
'Alpha' => [$sut, 'ABCDEFGHIKLMNOPQRSTVXYZabcdefghiklmnopqrstvxyz'],
'Symbols' => [$sut, '&"\'(-_)@-*/+.'],
'Unicode symbols' => [$sut, 'çàéè⁊ǷÞÐÆ'],
'Arabic' => [$sut, 'ضصثقفغعهخحجشسيبلاتنمكطئءؤرلاىةوزظذ'],
'Russian' => [$sut, 'русский'],
'Japanese' => [$sut, 'ろぬふあうえおやゆよわ゛へちついすかんなにらせれせ゜たqとしはきくまのりもろむてさそひこみねるめ!'],
];
}
/**
* {@inheritdoc}
*/
public function providerForInvalidInput(): array
{
$sut = new NotEmoji();
return [
'Smileys & People' => [$sut, '🤣'],
'Backhand Index Pointing Right with modifier' => [$sut, '👉🏿'],
'Santa Claus with modifier' => [$sut, '🎅🏾'],
'Man Frowning with modifier' => [$sut, '🙍🏻‍♂️'],
'Animals & Nature' => [$sut, '🐵'],
'Food & Drink' => [$sut, '🍎'],
'Travel & Places' => [$sut, '⛰️'],
'Activities' => [$sut, '🎈'],
'Objects' => [$sut, '📢'],
'Symbols from Unicode 4.0' => [$sut, '⚠️'],
'Symbols from Unicode 7.0' => [$sut, '⏺️'],
'Symbols from Unicode 6.0' => [$sut, '✅'],
'Flags Emoji 1.0' => [$sut, '🇹🇳'],
'Flags Emoji 4.0' => [$sut, '🏳️‍🌈'],
'Flags Emoji 5.0' => [$sut, '🏴󠁧󠁢󠁥󠁮󠁧󠁿'],
'Flags Emoji 11.0' => [$sut, '🏴‍☠️'],
'Flags' => [$sut, '🇹🇳'],
'Mixed with text' => [$sut, 'this is a pizza 🍕'],
'Array' => [$sut, []],
'Bool' => [$sut, true],
'Object' => [$sut, new stdClass()],
];
}
}