├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── DEPLOY.md ├── EMOJIS.md ├── LICENSE.md ├── README.md ├── charConverter.js ├── emoji-table-generator ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── vdurmont │ └── emoji │ └── TableGenerator.java ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── vdurmont │ │ └── emoji │ │ ├── Emoji.java │ │ ├── EmojiLoader.java │ │ ├── EmojiManager.java │ │ ├── EmojiParser.java │ │ ├── EmojiTrie.java │ │ └── Fitzpatrick.java └── resources │ └── emojis.json └── test ├── java └── com │ └── vdurmont │ └── emoji │ ├── EmojiJsonTest.java │ ├── EmojiLoaderTest.java │ ├── EmojiManagerTest.java │ ├── EmojiParserTest.java │ └── TestTools.java └── resources └── emoji-test.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Java 2 | target 3 | 4 | # IntelliJ files 5 | *.iml 6 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: java 3 | dist: precise 4 | jdk: 5 | - openjdk6 6 | - oraclejdk7 7 | - openjdk7 8 | - oraclejdk8 9 | after_success: 10 | - mvn clean cobertura:cobertura coveralls:cobertura -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v5.1.1 4 | 5 | - Bugfix: respect fitzpatrick modifier when extracting emojis (thanks @sullis) 6 | 7 | ## v5.1.0 8 | 9 | - Many performance improvements to the parsing of the emojis (thanks @freva) 10 | - Add a `containsEmoji` function (thanks @freva!) 11 | 12 | ## v5.0.0 13 | 14 | - Fix the HTML to Unicode parser to always parse the longer emojis (thanks @freva) 15 | - Add alias for "pumpkin" (thanks @sullis) 16 | - Add a lot of missing flag emojis (thanks @ankitkariryaa) 17 | - Support for all emojis from Unicode 11.0 18 | - Support for all emojis from Unicode 10.0 19 | - Add a `EmojiParser.replaceAllEmojis` function (thanks @cbedoy) 20 | 21 | ## v4.0.0 22 | 23 | - Add "source code" strings to emoji json database 24 | - Fix some missing/out-of-order code points (thanks @BillyGalbreath) 25 | - Upgrade `org.json:json` dependency (thanks @PhotonQyv) 26 | - Update README with new emojis (thanks @jtobard) 27 | 28 | ## v3.3.0 29 | 30 | - Add `family_man_woman_girl_boy` emoji (thanks @freva) 31 | - Fix `EmojiManager.isEmoji` to support fitzpatrick modifiers (thanks @freva) 32 | - Fixed several emojis that had the wrong `support_fitzpatrick` flag (thanks @Tapchicoma) 33 | - Add some tests to avoid duplicate aliases 34 | - Fixed several duplicated aliases in the emoji DB 35 | 36 | ## v3.2.0 37 | 38 | - Fixed Poland flag (thanks @Sheigutn) 39 | - Improvements to the smile emojis (thanks @miquelbeltran) 40 | - Add a bunch of emojis from Apple iOS 10.2 release 41 | - Fix some missing fitzpatrick modifiers 42 | - Add an `EmojiManager.isOnlyEmojis()` method 43 | 44 | ## v3.1.3 45 | 46 | - Removed all variance selectors from the JSON database. Thanks @roberterdin ! 47 | 48 | ## v3.1.2 49 | 50 | - Additions and updates to the emoji database (victory hand now supports fitzpatrick, adds Saint Vincent Grenadines' flag, add the regional indicator symbols). Thanks @lologist ! 51 | - Force the database to be loaded in UTF-8. 52 | - Enable the extension of the `EmojiParser` class. 53 | 54 | ## v3.1.1 55 | 56 | - Add the ability to provide a custom `EmojiTransformer` that will enable developers to add their custom emoji replacement methods. Thanks @freva ! 57 | 58 | ## v3.1.0 59 | 60 | - Add fitzpatrick support for 👃 ("nose") and 👂 ("ear") 61 | - Fix duplicated "sunglasses" alias 62 | - Performance improvements (using a Trie structure) 63 | - Parsing support for multiple emojis (such as "family_man_woman_boy") 64 | - Fix `EmojiManager.getAll()` that returned some duplicates 65 | - Use a BufferedReader to load the database 66 | 67 | ## v3.0.0 68 | 69 | Update the emoji database to support the additions of iOS 9.1 70 | 71 | ## v2.2.1 72 | 73 | Fix the `htmlDec` and `htmlHex` codes for the multiple emojis (such as `family (man, man, girl, boy)`) 74 | 75 | ## v2.2.0 76 | 77 | Rollback dependency org.json:json to 20140107 to keep the compatibility with Java 6 & 7 78 | 79 | ## v2.1.0 80 | 81 | - Add methods: 82 | - `EmojiParser#removeAllEmojis(String)` 83 | - `EmojiParser#removeAllEmojisExcept(String, Collection)` 84 | - `EmojiParser#removeEmojis(String, Collection)` 85 | - Upgrade dependency org.json:json 86 | 87 | ## v2.0.1 88 | 89 | Bug fix on the :-1: emoji 90 | 91 | ## v2.0.0 92 | 93 | - Update of the emoji database 94 | - Add 14 new family emojis (man_man_boy, woman_woman_girl, etc.) 95 | - Add 4 new couple emojis 96 | - Add the "vulcan_salute" and "middle_finger" emojis 97 | - Add 198 flags 98 | - Addition of the support for the diversity emojis (Fitzpatrick modifiers) 99 | - Removal of the deprecated methods `Emoji#getHtml` and `EmojiParser#parseToHtml` 100 | - Improvements in the javadoc 101 | 102 | ## v1.1.1 103 | 104 | Closing the stream used to read the emoji database in `EmojiManager.java` 105 | 106 | ## v1.1.0 107 | 108 | - Update of the emoji database 109 | - Adding support for HTML hexadecimal: 110 | - `Emoji#getHtmlHexadecimal` 111 | - `EmojiParser#parseToHtmlHexadecimal` 112 | - The old HTML support is now HTML decimal: 113 | - Deprecating `Emoji#getHtml` (replaced by `Emoji#getHtmlDecimal`) 114 | - Deprecating `EmojiParser#parseToHtml` (replaced by `EmojiParser#parseToHtmlDecimal`) 115 | 116 | ## v1.0.1 117 | 118 | Bug fix on the :+1: emoji 119 | 120 | ## v1.0.0 121 | 122 | First release. 123 | -------------------------------------------------------------------------------- /DEPLOY.md: -------------------------------------------------------------------------------- 1 | # Deployment Notes 2 | 3 | *This is intended as a reminder for @vdurmont to deploy this library to maven central.* 4 | 5 | ## zshrc 6 | 7 | Add this, it help: 8 | ``` 9 | # Needed for gpg when releasing stuff on maven central 10 | # https://github.com/keybase/keybase-issues/issues/2798 11 | export GPG_TTY=$(tty) 12 | ``` 13 | 14 | ## GPG signing 15 | 16 | Import your gpg key: `gpg --import path/to/my/private/key.asc` 17 | 18 | ## Sonatype auth 19 | 20 | Setup your `~/.m2/settings.xml` file: 21 | 22 | ```xml 23 | 27 | 28 | 29 | ossrh 30 | MY_USERNAME 31 | MY_SONATYPE_PASSWORD 32 | 33 | 34 | 35 | ``` 36 | 37 | ## Deploy! 38 | 39 | ``` 40 | mvn clean deploy -DperformRelease=true -Prelease 41 | ``` 42 | -------------------------------------------------------------------------------- /EMOJIS.md: -------------------------------------------------------------------------------- 1 | ## Available Emojis 2 | 3 | Here is a table of the available emojis and their aliases. 4 | 5 | | Emoji | Aliases | Emoji | Aliases | 6 | | :---: | ------- | :---: | ------- | 7 | | 🏴󠁧󠁢󠁥󠁮󠁧󠁿 | gbeng | 🏴󠁧󠁢󠁳󠁣󠁴󠁿 | gbsct | 8 | | 🏴󠁧󠁢󠁷󠁬󠁳󠁿 | gbwls | 🏴󠁵󠁳󠁴󠁸󠁿 | ustx | 9 | | 👨‍👩‍👦‍👦 | family_man_woman_boy_boy | 👨‍👩‍👧‍👧 | family_man_woman_girl_girl | 10 | | 👨‍👩‍👧‍👦 | family_man_woman_girl_boy | 👩‍👩‍👧‍👦 | family_woman_woman_girl_boy | 11 | | 👩‍👩‍👦‍👦 | family_woman_woman_boy_boy | 👩‍👩‍👧‍👧 | family_woman_woman_girl_girl | 12 | | 👨‍👨‍👧‍👦 | family_man_man_girl_boy | 👨‍👨‍👦‍👦 | family_man_man_boy_boy | 13 | | 👨‍👨‍👧‍👧 | family_man_man_girl_girl | 👩‍❤️‍💋‍👩 | couplekiss_woman_woman | 14 | | 👨‍❤️‍💋‍👨 | couplekiss_man_man | 👨‍👩‍👦 | family_man_woman_boy | 15 | | 👨‍👩‍👧 | family_man_woman_girl | 👩‍👩‍👦 | family_woman_woman_boy | 16 | | 👩‍👩‍👧 | family_woman_woman_girl | 👨‍👨‍👦 | family_man_man_boy | 17 | | 👨‍👨‍👧 | family_man_man_girl | 👩‍❤️‍👩 | couple_with_heart_woman_woman | 18 | | 👨‍❤️‍👨 | couple_with_heart_man_man | 🏳️‍🌈 | rainbow_flag, pride_flag | 19 | | 🏌️‍♂️ | man_golfer, male_golfer, man_golfing, male_golfing | 🏌️‍♀️ | woman_golfer, female_golfer, woman_golfing, female_golfing | 20 | | ♾🏴‍☠️ | pirate_flag, jolly_roger | 🙇‍♀️ | woman_bow, female_bow | 21 | | 🙇‍♂️ | man_bow, male_bow | 👁‍🗨 | eye_in_speech_bubble, i_am_a_witness | 22 | | 🤸‍♂️ | man_doing_cartwheel, male_doing_cartwheel | 🤸‍♀️ | woman_doing_cartwheel, female_doing_cartwheel | 23 | | 🤼‍♂️ | man_wrestlers, male_wrestlers | 🤼‍♀️ | woman_wrestlers, female_wrestlers | 24 | | 🤽‍♂️ | man_water_polo, male_water_polo | 🤽‍♀️ | woman_water_polo, female_water_polo | 25 | | 🤾‍♂️ | man_handball, male_handball | 🤾‍♀️ | woman_handball, female_handball | 26 | | 🤹‍♂️ | man_juggling, male_juggling | 🤹‍♀️ | woman_juggling, female_juggling | 27 | | 👨‍⚕️ | male_health_worker, man_health_worker | 👩‍⚕️ | female_health_worker, woman_health_worker | 28 | | 👨‍🎓 | male_student, man_student | 👩‍🎓 | female_student, woman_student | 29 | | 👨‍🏫 | male_teacher, man_teacher | 👩‍🏫 | female_teacher, woman_teacher | 30 | | 👨‍🌾 | male_farmer, man_farmer | 👩‍🌾 | female_farmer, woman_farmer | 31 | | 👨‍🍳 | male_cook, man_cook | 👩‍🍳 | female_cook, woman_cook | 32 | | 👨‍🔧 | male_mechanic, man_mechanic | 👩‍🔧 | female_mechanic, woman_mechanic | 33 | | 👨‍🏭 | male_factory_worker, man_factory_worker | 👩‍🏭 | female_factory_worker, woman_factory_worker | 34 | | 👨‍💼 | male_office_worker, man_office_worker | 👩‍💼 | female_office_worker, woman_office_worker | 35 | | 👨‍🔬 | male_scientist, man_scientist | 👩‍🔬 | female_scientist, woman_scientist | 36 | | 👨‍💻 | male_technologist, man_technologist | 👩‍💻 | female_technologist, woman_technologist | 37 | | 👨‍🎤 | male_singer, man_singer | 👩‍🎤 | female_singer, woman_singer | 38 | | 👨‍🎨 | male_artist, man_artist | 👩‍🎨 | female_artist, woman_artist | 39 | | 👨‍✈️ | male_pilot, man_pilot | 👩‍✈️ | female_pilot, woman_pilot | 40 | | 👨‍🚀 | male_astronaut, man_astronaut | 👩‍🚀 | female_astronaut, woman_astronaut | 41 | | 👨‍🚒 | male_firefighter, man_firefighter | 👩‍🚒 | female_firefighter, woman_firefighter | 42 | | 🤦‍♀️ | female_facepalm, woman_facepalm | 🤷‍♂️ | male_shrug, man_shrug | 43 | | 🤷‍♀️ | female_shrug, woman_shrug | 👨‍⚖️ | man_judge, male_judge | 44 | | 👩‍⚖️ | woman_judge, female_judge | 🧙‍♂️ | man_mage, wizard, sorcerer | 45 | | 🧙‍♀️ | woman_mage, witch, sorceress | 🧚‍♂️ | man_fairy | 46 | | 🧚‍♀️ | woman_fairy | 🧛‍♂️ | man_vampire, dracula | 47 | | 🧛‍♀️ | woman_vampire | 🧜‍♂️ | merman, merboy, man_merperson | 48 | | 🧜‍♀️ | mermaid, mergirl, woman_merperson | 🧝‍♂️ | man_elf, legolas | 49 | | 🧝‍♀️ | woman_elf | 🧞‍♂️ | man_genie | 50 | | 🧞‍♀️ | woman_genie | 🧟‍♂️ | man_zombie | 51 | | 🧟‍♀️ | woman_zombie | 🧖‍♂️ | man_in_steamy_room, man_in_sauna | 52 | | 🧖‍♀️ | woman_in_steamy_room, woman_in_sauna | 🧗‍♂️ | man_climbing, man_climber, man_rock_climbing | 53 | | 🧗‍♀️ | woman_climbing, woman_climber, woman_rock_climbing | 🧘‍♂️ | man_in_lotus_position, man_yoga, man_meditation | 54 | | 🧘‍♀️ | woman_in_lotus_position, woman_yoga, woman_meditation | 👨‍🦰 | man_with_red_hair, man_redhead, man_ginger | 55 | | 👩‍🦰 | woman_with_red_hair, woman_redhead, woman_ginger | 👨‍🦱 | man_with_curly_hair | 56 | | 👩‍🦱 | woman_with_curly_hair | 👨‍🦳 | man_with_white_hair, man_with_gray_hair, man_with_grey_hair | 57 | | 👩‍🦳 | woman_with_white_hair, woman_with_gray_hair, woman_with_grey_hair | 👨‍🦲 | man_with_no_hair, bald_man | 58 | | 👩‍🦲 | woman_with_no_hair, bald_woman | 🦸‍♂️ | man_superhero | 59 | | 🦸‍♀️ | woman_superhero | 🦹‍♂️ | man_supervillain | 60 | | 🦹‍♀️ | woman_supervillain | 🇦🇨 | ac | 61 | | 🇦🇩 | ad | 🇦🇪 | ae | 62 | | 🇦🇫 | af | 🇦🇬 | ag | 63 | | 🇦🇮 | ai | 🇦🇱 | al | 64 | | 🇦🇲 | am | 🇦🇴 | ao | 65 | | 🇦🇶 | aq | 🇦🇷 | ar | 66 | | 🇦🇸 | as | 🇦🇹 | at | 67 | | 🇦🇺 | au | 🇦🇼 | aw | 68 | | 🇦🇽 | ax | 🇦🇿 | az | 69 | | 🇧🇦 | ba | 🇧🇧 | bb | 70 | | 🇧🇩 | bd | 🇧🇪 | be | 71 | | 🇧🇫 | bf | 🇧🇬 | bg | 72 | | 🇧🇭 | bh | 🇧🇮 | bi | 73 | | 🇧🇯 | bj | 🇧🇱 | bl | 74 | | 🇧🇲 | bm | 🇧🇳 | bn | 75 | | 🇧🇴 | bo | 🇧🇶 | bq | 76 | | 🇧🇷 | br | 🇧🇸 | bs | 77 | | 🇧🇹 | bt | 🇧🇻 | bv | 78 | | 🇧🇼 | bw | 🇧🇾 | by | 79 | | 🇧🇿 | bz | 🇨🇦 | ca | 80 | | 🇨🇨 | cc | 🇨🇩 | cd_flag | 81 | | 🇨🇫 | cf | 🇨🇬 | cg | 82 | | 🇨🇭 | ch | 🇨🇮 | ci | 83 | | 🇨🇰 | ck | 🇨🇱 | cl_flag | 84 | | 🇨🇲 | cm | 🇨🇳 | cn | 85 | | 🇨🇴 | co | 🇨🇵 | cp | 86 | | 🇨🇷 | cr | 🇨🇺 | cu | 87 | | 🇨🇻 | cv | 🇨🇼 | cw | 88 | | 🇨🇽 | cx | 🇨🇾 | cy | 89 | | 🇨🇿 | cz | 🇩🇪 | de | 90 | | 🇩🇬 | dg | 🇩🇯 | dj | 91 | | 🇩🇰 | dk | 🇩🇲 | dm | 92 | | 🇩🇴 | do | 🇩🇿 | dz | 93 | | 🇪🇦 | ea | 🇪🇨 | ec | 94 | | 🇪🇪 | ee | 🇪🇬 | eg | 95 | | 🇪🇭 | eh | 🇪🇷 | er | 96 | | 🇪🇸 | es | 🇪🇹 | et | 97 | | 🇪🇺 | eu | 🇫🇮 | fi | 98 | | 🇫🇯 | fj | 🇫🇰 | fk | 99 | | 🇫🇲 | fm | 🇫🇴 | fo | 100 | | 🇫🇷 | fr | 🇬🇦 | ga | 101 | | 🇬🇧 | gb | 🇬🇩 | gd | 102 | | 🇬🇪 | ge | 🇬🇫 | gf | 103 | | 🇬🇬 | gg | 🇬🇭 | gh | 104 | | 🇬🇮 | gi | 🇬🇱 | gl | 105 | | 🇬🇲 | gm | 🇬🇳 | gn | 106 | | 🇬🇵 | gp | 🇬🇶 | gq | 107 | | 🇬🇷 | gr | 🇬🇸 | gs | 108 | | 🇬🇹 | gt | 🇬🇺 | gu | 109 | | 🇬🇼 | gw | 🇬🇾 | gy | 110 | | 🇭🇰 | hk | 🇭🇲 | hm | 111 | | 🇭🇳 | hn | 🇭🇷 | hr | 112 | | 🇭🇹 | ht | 🇭🇺 | hu | 113 | | 🇮🇨 | ic | 🇮🇩 | id_flag | 114 | | 🇮🇪 | ie | 🇮🇱 | il | 115 | | 🇮🇲 | im | 🇮🇳 | in | 116 | | 🇮🇴 | io | 🇮🇶 | iq | 117 | | 🇮🇷 | ir | 🇮🇸 | is | 118 | | 🇮🇹 | it | 🇯🇪 | je | 119 | | 🇯🇲 | jm | 🇯🇴 | jo | 120 | | 🇯🇵 | jp | 🇰🇪 | ke | 121 | | 🇰🇬 | kg | 🇰🇭 | kh | 122 | | 🇰🇮 | ki | 🇰🇲 | km | 123 | | 🇰🇳 | kn | 🇰🇵 | kp | 124 | | 🇰🇷 | kr | 🇰🇼 | kw | 125 | | 🇰🇾 | ky | 🇰🇿 | kz | 126 | | 🇱🇦 | la | 🇱🇧 | lb | 127 | | 🇱🇨 | lc | 🇱🇮 | li | 128 | | 🇱🇰 | lk | 🇱🇷 | lr | 129 | | 🇱🇸 | ls | 🇱🇹 | lt | 130 | | 🇱🇺 | lu | 🇱🇻 | lv | 131 | | 🇱🇾 | ly | 🇲🇦 | ma | 132 | | 🇲🇨 | mc | 🇲🇩 | md | 133 | | 🇲🇪 | me | 🇲🇫 | mf | 134 | | 🇲🇬 | mg | 🇲🇭 | mh | 135 | | 🇲🇰 | mk | 🇲🇱 | ml | 136 | | 🇲🇲 | mm | 🇲🇳 | mn | 137 | | 🇲🇴 | mo | 🇲🇵 | mp | 138 | | 🇲🇶 | mq | 🇲🇷 | mr | 139 | | 🇲🇸 | ms | 🇲🇹 | mt | 140 | | 🇲🇺 | mu | 🇲🇻 | mv | 141 | | 🇲🇼 | mw | 🇲🇽 | mx | 142 | | 🇲🇾 | my | 🇲🇿 | mz | 143 | | 🇳🇦 | na | 🇳🇨 | nc | 144 | | 🇳🇪 | ne | 🇳🇫 | nf | 145 | | 🇳🇬 | ng | 🇳🇮 | ni | 146 | | 🇳🇱 | nl | 🇳🇴 | no | 147 | | 🇳🇵 | np | 🇳🇷 | nr | 148 | | 🇳🇺 | nu | 🇳🇿 | nz | 149 | | 🇴🇲 | om | 🇵🇦 | pa | 150 | | 🇵🇪 | pe | 🇵🇫 | pf | 151 | | 🇵🇬 | pg | 🇵🇭 | ph | 152 | | 🇵🇰 | pk | 🇵🇱 | pl | 153 | | 🇵🇲 | pm | 🇵🇳 | pn | 154 | | 🇵🇷 | pr | 🇵🇸 | ps | 155 | | 🇵🇹 | pt | 🇵🇼 | pw | 156 | | 🇵🇾 | py | 🇶🇦 | qa | 157 | | 🇷🇪 | re | 🇷🇴 | ro | 158 | | 🇷🇸 | rs | 🇷🇺 | ru | 159 | | 🇷🇼 | rw | 🇸🇦 | sa_flag | 160 | | 🇸🇧 | sb | 🇸🇨 | sc | 161 | | 🇸🇩 | sd | 🇸🇪 | se | 162 | | 🇸🇬 | sg | 🇸🇭 | sh | 163 | | 🇸🇮 | si | 🇸🇯 | sj | 164 | | 🇸🇰 | sk | 🇸🇱 | sl | 165 | | 🇸🇲 | sm | 🇸🇳 | sn | 166 | | 🇸🇴 | so | 🇸🇷 | sr | 167 | | 🇸🇸 | ss | 🇸🇹 | st | 168 | | 🇸🇻 | sv | 🇸🇽 | sx | 169 | | 🇸🇾 | sy | 🇸🇿 | sz | 170 | | 🇹🇦 | ta | 🇹🇨 | tc | 171 | | 🇹🇩 | td | 🇹🇫 | tf | 172 | | 🇹🇬 | tg | 🇹🇭 | th | 173 | | 🇹🇯 | tj | 🇹🇰 | tk | 174 | | 🇹🇱 | tl | 🇹🇲 | tm_flag | 175 | | 🇹🇳 | tn | 🇹🇴 | to | 176 | | 🇹🇷 | tr | 🇹🇹 | tt | 177 | | 🇹🇻 | tv_flag | 🇹🇼 | tw | 178 | | 🇹🇿 | tz | 🇺🇦 | ua | 179 | | 🇺🇬 | ug | 🇺🇲 | um | 180 | | 🇺🇳 | un | 🇺🇸 | us | 181 | | 🇺🇾 | uy | 🇺🇿 | uz | 182 | | 🇻🇦 | va | 🇻🇨 | vc | 183 | | 🇻🇪 | ve | 🇻🇬 | vg | 184 | | 🇻🇮 | vi | 🇻🇳 | vn | 185 | | 🇻🇺 | vu | 🇼🇫 | wf | 186 | | 🇼🇸 | ws | 🇽🇰 | xk | 187 | | 🇾🇪 | ye | 🇾🇹 | yt | 188 | | 🇿🇦 | za | 🇿🇲 | zm | 189 | | 🇿🇼 | zw | 😄 | smile | 190 | | 😃 | smiley | 😀 | grinning | 191 | | 😊 | blush | 😉 | wink | 192 | | 😍 | heart_eyes | 😘 | kissing_heart | 193 | | 😚 | kissing_closed_eyes | 😗 | kissing | 194 | | 😙 | kissing_smiling_eyes | 😜 | stuck_out_tongue_winking_eye | 195 | | 😝 | stuck_out_tongue_closed_eyes | 😛 | stuck_out_tongue | 196 | | 😳 | flushed | 😁 | grin | 197 | | 😔 | pensive | 😌 | relieved | 198 | | 😒 | unamused | 😞 | disappointed | 199 | | 😣 | persevere | 😢 | cry | 200 | | 😂 | joy | 😭 | sob | 201 | | 😪 | sleepy | 😥 | disappointed_relieved | 202 | | 😰 | cold_sweat | 😅 | sweat_smile | 203 | | 😓 | sweat | 😩 | weary | 204 | | 😫 | tired_face | 😨 | fearful | 205 | | 😱 | scream | 😠 | angry | 206 | | 😡 | rage | 😤 | triumph | 207 | | 😖 | confounded | 😆 | laughing, satisfied | 208 | | 😋 | yum | 😷 | mask | 209 | | 😎 | sunglasses | 😴 | sleeping | 210 | | 😵 | dizzy_face | 😲 | astonished | 211 | | 😟 | worried | 😦 | frowning | 212 | | 😧 | anguished | 😈 | smiling_imp | 213 | | 👿 | imp | 😮 | open_mouth | 214 | | 😬 | grimacing | 😐 | neutral_face | 215 | | 😕 | confused | 😯 | hushed | 216 | | 😶 | no_mouth | 😇 | innocent | 217 | | 😏 | smirk | 😑 | expressionless | 218 | | 👲 | man_with_gua_pi_mao | 👳 | man_with_turban | 219 | | 👮 | cop | 👷 | construction_worker | 220 | | 💂 | guardsman | 👶 | baby | 221 | | 👦 | boy | 👧 | girl | 222 | | 👨 | man | 👩 | woman | 223 | | 👴 | older_man | 👵 | older_woman | 224 | | 👱 | person_with_blond_hair | 👼 | angel | 225 | | 👸 | princess | 😺 | smiley_cat | 226 | | 😸 | smile_cat | 😻 | heart_eyes_cat | 227 | | 😽 | kissing_cat | 😼 | smirk_cat | 228 | | 🙀 | scream_cat | 😿 | crying_cat_face | 229 | | 😹 | joy_cat | 😾 | pouting_cat | 230 | | 👹 | japanese_ogre | 👺 | japanese_goblin | 231 | | 🙈 | see_no_evil | 🙉 | hear_no_evil | 232 | | 🙊 | speak_no_evil | 💀 | skull | 233 | | 👽 | alien | 💩 | hankey, poop, shit | 234 | | 🔥 | fire | 🌟 | star2 | 235 | | 💫 | dizzy | 💥 | boom, collision | 236 | | 💢 | anger | 💦 | sweat_drops | 237 | | 💧 | droplet | 💤 | zzz | 238 | | 💨 | dash | 👂 | ear | 239 | | 👀 | eyes | 👃 | nose | 240 | | 👅 | tongue | 👄 | lips | 241 | | 👍 | +1, thumbsup | 👎 | -1, thumbsdown | 242 | | 👌 | ok_hand | 👊 | facepunch, punch | 243 | | 👋 | wave | 👐 | open_hands | 244 | | 👆 | point_up_2 | 👇 | point_down | 245 | | 👉 | point_right | 👈 | point_left | 246 | | 🙌 | raised_hands | 🙏 | pray | 247 | | 👏 | clap | 💪 | muscle | 248 | | 🚶 | walking | 🏃 | runner, running | 249 | | 💃 | dancer | 👫 | couple | 250 | | 👪 | family | 👬 | two_men_holding_hands | 251 | | 👭 | two_women_holding_hands | 💏 | couplekiss | 252 | | 💑 | couple_with_heart | 👯 | dancers | 253 | | 🙆 | ok_woman | 🙅 | no_good | 254 | | 💁 | information_desk_person | 🙋 | raising_hand | 255 | | 💆 | massage | 💇 | haircut | 256 | | 💅 | nail_care | 👰 | bride_with_veil | 257 | | 🙎 | person_with_pouting_face | 🙍 | person_frowning | 258 | | 🙇 | bow | 🎩 | tophat | 259 | | 👑 | crown | 👒 | womans_hat | 260 | | 👟 | athletic_shoe | 👞 | mans_shoe, shoe | 261 | | 👡 | sandal | 👠 | high_heel | 262 | | 👢 | boot | 👕 | shirt, tshirt | 263 | | 👔 | necktie | 👚 | womans_clothes | 264 | | 👗 | dress | 🎽 | running_shirt_with_sash | 265 | | 👖 | jeans | 👘 | kimono | 266 | | 👙 | bikini | 💼 | briefcase | 267 | | 👜 | handbag | 👝 | pouch | 268 | | 👛 | purse | 👓 | eyeglasses | 269 | | 🎀 | ribbon | 🌂 | closed_umbrella | 270 | | 💄 | lipstick | 💛 | yellow_heart | 271 | | 💙 | blue_heart | 💜 | purple_heart | 272 | | 💚 | green_heart | 💔 | broken_heart | 273 | | 💗 | heartpulse | 💓 | heartbeat | 274 | | 💕 | two_hearts | 💖 | sparkling_heart | 275 | | 💞 | revolving_hearts | 💘 | cupid | 276 | | 💌 | love_letter | 💋 | kiss | 277 | | 💍 | ring | 💎 | gem | 278 | | 👤 | bust_in_silhouette | 👥 | busts_in_silhouette | 279 | | 💬 | speech_balloon | 👣 | footprints | 280 | | 💭 | thought_balloon | 🐶 | dog | 281 | | 🐺 | wolf | 🐱 | cat | 282 | | 🐭 | mouse | 🐹 | hamster | 283 | | 🐰 | rabbit | 🐸 | frog | 284 | | 🐯 | tiger | 🐨 | koala | 285 | | 🐻 | bear | 🐷 | pig | 286 | | 🐽 | pig_nose | 🐮 | cow | 287 | | 🐗 | boar | 🐵 | monkey_face | 288 | | 🐒 | monkey | 🐴 | horse | 289 | | 🐑 | sheep | 🐘 | elephant | 290 | | 🐼 | panda_face | 🐧 | penguin | 291 | | 🐦 | bird | 🐤 | baby_chick | 292 | | 🐥 | hatched_chick | 🐣 | hatching_chick | 293 | | 🐔 | chicken | 🐍 | snake | 294 | | 🐢 | turtle | 🐛 | bug | 295 | | 🐝 | bee, honeybee | 🐜 | ant | 296 | | 🐞 | beetle | 🐌 | snail | 297 | | 🐙 | octopus | 🐚 | shell | 298 | | 🐠 | tropical_fish | 🐟 | fish | 299 | | 🐬 | dolphin, flipper | 🐳 | whale | 300 | | 🐋 | whale2 | 🐄 | cow2 | 301 | | 🐏 | ram | 🐀 | rat | 302 | | 🐃 | water_buffalo | 🐅 | tiger2 | 303 | | 🐇 | rabbit2 | 🐉 | dragon | 304 | | 🐎 | racehorse | 🐐 | goat | 305 | | 🐓 | rooster | 🐕 | dog2 | 306 | | 🐖 | pig2 | 🐁 | mouse2 | 307 | | 🐂 | ox | 🐲 | dragon_face | 308 | | 🐡 | blowfish | 🐊 | crocodile | 309 | | 🐫 | camel | 🐪 | dromedary_camel | 310 | | 🐆 | leopard | 🐈 | cat2 | 311 | | 🐩 | poodle | 🐾 | feet, paw_prints | 312 | | 💐 | bouquet | 🌸 | cherry_blossom | 313 | | 🌷 | tulip | 🍀 | four_leaf_clover | 314 | | 🌹 | rose | 🌻 | sunflower | 315 | | 🌺 | hibiscus | 🍁 | maple_leaf | 316 | | 🍃 | leaves | 🍂 | fallen_leaf | 317 | | 🌿 | herb | 🌾 | ear_of_rice | 318 | | 🍄 | mushroom | 🌵 | cactus | 319 | | 🌴 | palm_tree | 🌲 | evergreen_tree | 320 | | 🌳 | deciduous_tree | 🌰 | chestnut | 321 | | 🌱 | seedling | 🌼 | blossom | 322 | | 🌐 | globe_with_meridians | 🌞 | sun_with_face | 323 | | 🌝 | full_moon_with_face | 🌚 | new_moon_with_face | 324 | | 🌑 | new_moon | 🌒 | waxing_crescent_moon | 325 | | 🌓 | first_quarter_moon | 🌔 | moon, waxing_gibbous_moon | 326 | | 🌕 | full_moon | 🌖 | waning_gibbous_moon | 327 | | 🌗 | last_quarter_moon | 🌘 | waning_crescent_moon | 328 | | 🌜 | last_quarter_moon_with_face | 🌛 | first_quarter_moon_with_face | 329 | | 🌙 | crescent_moon | 🌍 | earth_africa | 330 | | 🌎 | earth_americas | 🌏 | earth_asia | 331 | | 🌋 | volcano | 🌌 | milky_way | 332 | | 🌠 | stars | 🌀 | cyclone | 333 | | 🌁 | foggy | 🌈 | rainbow | 334 | | 🌊 | ocean | 🎍 | bamboo | 335 | | 💝 | gift_heart | 🎎 | dolls | 336 | | 🎒 | school_satchel | 🎓 | mortar_board | 337 | | 🎏 | flags | 🎆 | fireworks | 338 | | 🎇 | sparkler | 🎐 | wind_chime | 339 | | 🎑 | rice_scene | 🎃 | jack_o_lantern | 340 | | 👻 | ghost | 🎅 | santa | 341 | | 🎄 | christmas_tree | 🎁 | gift | 342 | | 🎋 | tanabata_tree | 🎉 | tada | 343 | | 🎊 | confetti_ball | 🎈 | balloon | 344 | | 🎌 | crossed_flags | 🔮 | crystal_ball | 345 | | 🎥 | movie_camera | 📷 | camera | 346 | | 📹 | video_camera | 📼 | vhs | 347 | | 💿 | cd | 📀 | dvd | 348 | | 💽 | minidisc | 💾 | floppy_disk | 349 | | 💻 | computer | 📱 | iphone | 350 | | 📞 | telephone_receiver | 📟 | pager | 351 | | 📠 | fax | 📡 | satellite_antenna | 352 | | 📺 | tv | 📻 | radio | 353 | | 🔊 | loud_sound | 🔉 | sound | 354 | | 🔈 | speaker | 🔇 | mute | 355 | | 🔔 | bell | 🔕 | no_bell | 356 | | 📢 | loudspeaker | 📣 | mega | 357 | | 🔓 | unlock | 🔒 | lock | 358 | | 🔏 | lock_with_ink_pen | 🔐 | closed_lock_with_key | 359 | | 🔑 | key | 🔎 | mag_right | 360 | | 💡 | bulb | 🔦 | flashlight | 361 | | 🔆 | high_brightness | 🔅 | low_brightness | 362 | | 🔌 | electric_plug | 🔋 | battery | 363 | | 🔍 | mag | 🛁 | bathtub | 364 | | 🛀 | bath | 🚿 | shower | 365 | | 🚽 | toilet | 🔧 | wrench | 366 | | 🔩 | nut_and_bolt | 🔨 | hammer | 367 | | 🚪 | door | 🚬 | smoking | 368 | | 💣 | bomb | 🔫 | gun | 369 | | 🔪 | hocho, knife | 💊 | pill | 370 | | 💉 | syringe | 💰 | moneybag | 371 | | 💴 | yen | 💵 | dollar | 372 | | 💷 | pound | 💶 | euro | 373 | | 💳 | credit_card | 💸 | money_with_wings | 374 | | 📲 | calling | 📧 | e-mail | 375 | | 📥 | inbox_tray | 📤 | outbox_tray | 376 | | 📩 | envelope_with_arrow | 📨 | incoming_envelope | 377 | | 📯 | postal_horn | 📫 | mailbox | 378 | | 📪 | mailbox_closed | 📬 | mailbox_with_mail | 379 | | 📭 | mailbox_with_no_mail | 📮 | postbox | 380 | | 📦 | package | 📝 | memo, pencil | 381 | | 📄 | page_facing_up | 📃 | page_with_curl | 382 | | 📑 | bookmark_tabs | 📊 | bar_chart | 383 | | 📈 | chart_with_upwards_trend | 📉 | chart_with_downwards_trend | 384 | | 📜 | scroll | 📋 | clipboard | 385 | | 📅 | date | 📆 | calendar | 386 | | 📇 | card_index | 📁 | file_folder | 387 | | 📂 | open_file_folder | 📌 | pushpin | 388 | | 📎 | paperclip | 📏 | straight_ruler | 389 | | 📐 | triangular_ruler | 📕 | closed_book | 390 | | 📗 | green_book | 📘 | blue_book | 391 | | 📙 | orange_book | 📓 | notebook | 392 | | 📔 | notebook_with_decorative_cover | 📒 | ledger | 393 | | 📚 | books | 📖 | book, open_book | 394 | | 🔖 | bookmark | 📛 | name_badge | 395 | | 🔬 | microscope | 🔭 | telescope | 396 | | 📰 | newspaper | 🎨 | art | 397 | | 🎬 | clapper | 🎤 | microphone | 398 | | 🎧 | headphones | 🎼 | musical_score | 399 | | 🎵 | musical_note | 🎶 | notes | 400 | | 🎹 | musical_keyboard | 🎻 | violin | 401 | | 🎺 | trumpet | 🎷 | saxophone | 402 | | 🎸 | guitar | 👾 | space_invader | 403 | | 🎮 | video_game | 🃏 | black_joker | 404 | | 🎴 | flower_playing_cards | 🀄 | mahjong | 405 | | 🎲 | game_die | 🎯 | dart | 406 | | 🏈 | football | 🏀 | basketball | 407 | | 🎾 | tennis | 🎱 | 8ball | 408 | | 🏉 | rugby_football | 🎳 | bowling | 409 | | 🚵 | mountain_bicyclist | 🚴 | bicyclist | 410 | | 🏁 | checkered_flag | 🏇 | horse_racing | 411 | | 🏆 | trophy | 🎿 | ski | 412 | | 🏂 | snowboarder | 🏊 | swimmer | 413 | | 🏄 | surfer | 🎣 | fishing_pole_and_fish | 414 | | 🍵 | tea | 🍶 | sake | 415 | | 🍼 | baby_bottle | 🍺 | beer | 416 | | 🍻 | beers | 🍸 | cocktail | 417 | | 🍹 | tropical_drink | 🍷 | wine_glass | 418 | | 🍴 | fork_and_knife | 🍕 | pizza | 419 | | 🍔 | hamburger | 🍟 | fries | 420 | | 🍗 | poultry_leg | 🍖 | meat_on_bone | 421 | | 🍝 | spaghetti | 🍛 | curry | 422 | | 🍤 | fried_shrimp | 🍱 | bento | 423 | | 🍣 | sushi | 🍥 | fish_cake | 424 | | 🍙 | rice_ball | 🍘 | rice_cracker | 425 | | 🍚 | rice | 🍜 | ramen | 426 | | 🍲 | stew | 🍢 | oden | 427 | | 🍡 | dango | 🍳 | cooking | 428 | | 🍞 | bread | 🍩 | doughnut | 429 | | 🍮 | custard | 🍦 | icecream | 430 | | 🍨 | ice_cream | 🍧 | shaved_ice | 431 | | 🎂 | birthday | 🍰 | cake | 432 | | 🍪 | cookie | 🍫 | chocolate_bar | 433 | | 🍬 | candy | 🍭 | lollipop | 434 | | 🍯 | honey_pot | 🍎 | apple | 435 | | 🍏 | green_apple | 🍊 | tangerine | 436 | | 🍋 | lemon | 🍒 | cherries | 437 | | 🍇 | grapes | 🍉 | watermelon | 438 | | 🍓 | strawberry | 🍑 | peach | 439 | | 🍈 | melon | 🍌 | banana | 440 | | 🍐 | pear | 🍍 | pineapple | 441 | | 🍠 | sweet_potato | 🍆 | eggplant | 442 | | 🍅 | tomato | 🌽 | corn | 443 | | 🏠 | house | 🏡 | house_with_garden | 444 | | 🏫 | school | 🏢 | office | 445 | | 🏣 | post_office | 🏥 | hospital | 446 | | 🏦 | bank | 🏪 | convenience_store | 447 | | 🏩 | love_hotel | 🏨 | hotel | 448 | | 💒 | wedding | 🏬 | department_store | 449 | | 🏤 | european_post_office | 🌇 | city_sunrise | 450 | | 🌆 | city_sunset | 🏯 | japanese_castle | 451 | | 🏰 | european_castle | 🏭 | factory | 452 | | 🗼 | tokyo_tower | 🗾 | japan | 453 | | 🗻 | mount_fuji | 🌄 | sunrise_over_mountains | 454 | | 🌅 | sunrise | 🌃 | night_with_stars | 455 | | 🗽 | statue_of_liberty | 🌉 | bridge_at_night | 456 | | 🎠 | carousel_horse | 🎡 | ferris_wheel | 457 | | 🎢 | roller_coaster | 🚢 | ship | 458 | | 🚤 | speedboat | 🚣 | rowboat | 459 | | 🚀 | rocket | 💺 | seat | 460 | | 🚁 | helicopter | 🚂 | steam_locomotive | 461 | | 🚊 | tram | 🚉 | station | 462 | | 🚞 | mountain_railway | 🚆 | train2 | 463 | | 🚄 | bullettrain_side | 🚅 | bullettrain_front | 464 | | 🚈 | light_rail | 🚇 | metro | 465 | | 🚝 | monorail | 🚋 | train | 466 | | 🚃 | railway_car | 🚎 | trolleybus | 467 | | 🚌 | bus | 🚍 | oncoming_bus | 468 | | 🚙 | blue_car | 🚘 | oncoming_automobile | 469 | | 🚗 | car, red_car | 🚕 | taxi | 470 | | 🚖 | oncoming_taxi | 🚛 | articulated_lorry | 471 | | 🚚 | truck | 🚨 | rotating_light | 472 | | 🚓 | police_car | 🚔 | oncoming_police_car | 473 | | 🚒 | fire_engine | 🚑 | ambulance | 474 | | 🚐 | minibus | 🚲 | bike | 475 | | 🚡 | aerial_tramway | 🚟 | suspension_railway | 476 | | 🚠 | mountain_cableway | 🚜 | tractor | 477 | | 💈 | barber | 🚏 | busstop | 478 | | 🎫 | ticket | 🚦 | vertical_traffic_light | 479 | | 🚥 | traffic_light | 🚧 | construction | 480 | | 🔰 | beginner | 🏮 | izakaya_lantern, lantern | 481 | | 🎰 | slot_machine | 🗿 | moyai | 482 | | 🎪 | circus_tent | 🎭 | performing_arts | 483 | | 📍 | round_pushpin | 🚩 | triangular_flag_on_post | 484 | | 1⃣ | one | 2⃣ | two | 485 | | 3⃣ | three | 4⃣ | four | 486 | | 5⃣ | five | 6⃣ | six | 487 | | 7⃣ | seven | 8⃣ | eight | 488 | | 9⃣ | nine | 0⃣ | zero | 489 | | 🔟 | keycap_ten | 🔢 | 1234 | 490 | | #⃣ | hash | 🔣 | symbols | 491 | | 🔠 | capital_abcd | 🔡 | abcd | 492 | | 🔤 | abc | 🔄 | arrows_counterclockwise | 493 | | 🔼 | arrow_up_small | 🔽 | arrow_down_small | 494 | | 🆗 | ok | 🔀 | twisted_rightwards_arrows | 495 | | 🔁 | repeat | 🔂 | repeat_one | 496 | | 🆕 | new | 🆙 | up | 497 | | 🆒 | cool | 🆓 | free | 498 | | 🆖 | squared_ng | 📶 | signal_strength | 499 | | 🎦 | cinema | 🈁 | koko | 500 | | 🈯 | u6307 | 🈳 | u7a7a | 501 | | 🈵 | u6e80 | 🈴 | u5408 | 502 | | 🈲 | u7981 | 🉐 | ideograph_advantage | 503 | | 🈹 | u5272 | 🈺 | u55b6 | 504 | | 🈶 | u6709 | 🈚 | u7121 | 505 | | 🚻 | restroom | 🚹 | mens | 506 | | 🚺 | womens | 🚼 | baby_symbol | 507 | | 🚾 | wc | 🚰 | potable_water | 508 | | 🚮 | put_litter_in_its_place | 🅿 | parking | 509 | | 🚭 | no_smoking | 🈷 | u6708 | 510 | | 🈸 | u7533 | 🈂 | sa | 511 | | 🛂 | passport_control | 🛄 | baggage_claim | 512 | | 🛅 | left_luggage | 🛃 | customs | 513 | | 🉑 | accept | 🆑 | cl | 514 | | 🆘 | sos | 🆔 | id | 515 | | 🚫 | no_entry_sign | 🔞 | underage | 516 | | 📵 | no_mobile_phones | 🚯 | do_not_litter | 517 | | 🚱 | non-potable_water | 🚳 | no_bicycles | 518 | | 🚷 | no_pedestrians | 🚸 | children_crossing | 519 | | 💟 | heart_decoration | 🆚 | vs | 520 | | 📳 | vibration_mode | 📴 | mobile_phone_off | 521 | | 🅰 | a | 🅱 | b | 522 | | 🆎 | ab | 🅾 | o2 | 523 | | 💠 | diamond_shape_with_a_dot_inside | 🔯 | six_pointed_star | 524 | | 🏧 | atm | 💹 | chart | 525 | | 💲 | heavy_dollar_sign | 💱 | currency_exchange | 526 | | 🔝 | top | 🔚 | end | 527 | | 🔙 | back | 🔛 | on | 528 | | 🔜 | soon | 🔃 | arrows_clockwise | 529 | | 🕛 | clock12 | 🕧 | clock1230 | 530 | | 🕐 | clock1 | 🕜 | clock130 | 531 | | 🕑 | clock2 | 🕝 | clock230 | 532 | | 🕒 | clock3 | 🕞 | clock330 | 533 | | 🕓 | clock4 | 🕟 | clock430 | 534 | | 🕔 | clock5 | 🕠 | clock530 | 535 | | 🕕 | clock6 | 🕖 | clock7 | 536 | | 🕗 | clock8 | 🕘 | clock9 | 537 | | 🕙 | clock10 | 🕚 | clock11 | 538 | | 🕡 | clock630 | 🕢 | clock730 | 539 | | 🕣 | clock830 | 🕤 | clock930 | 540 | | 🕥 | clock1030 | 🕦 | clock1130 | 541 | | 💮 | white_flower | 💯 | 100 | 542 | | 🔘 | radio_button | 🔗 | link | 543 | | 🔱 | trident | 🔺 | small_red_triangle | 544 | | 🔲 | black_square_button | 🔳 | white_square_button | 545 | | 🔴 | red_circle | 🔵 | large_blue_circle | 546 | | 🔻 | small_red_triangle_down | 🔶 | large_orange_diamond | 547 | | 🔷 | large_blue_diamond | 🔸 | small_orange_diamond | 548 | | 🔹 | small_blue_diamond | 🇦 | regional_indicator_symbol_a | 549 | | 🇧 | regional_indicator_symbol_b | 🇨 | regional_indicator_symbol_c | 550 | | 🇩 | regional_indicator_symbol_d | 🇪 | regional_indicator_symbol_e | 551 | | 🇫 | regional_indicator_symbol_f | 🇬 | regional_indicator_symbol_g | 552 | | 🇭 | regional_indicator_symbol_h | 🇮 | regional_indicator_symbol_i | 553 | | 🇯 | regional_indicator_symbol_j | 🇰 | regional_indicator_symbol_k | 554 | | 🇱 | regional_indicator_symbol_l | 🇲 | regional_indicator_symbol_m | 555 | | 🇳 | regional_indicator_symbol_n | 🇴 | regional_indicator_symbol_o | 556 | | 🇵 | regional_indicator_symbol_p | 🇶 | regional_indicator_symbol_q | 557 | | 🇷 | regional_indicator_symbol_r | 🇸 | regional_indicator_symbol_s | 558 | | 🇹 | regional_indicator_symbol_t | 🇺 | regional_indicator_symbol_u | 559 | | 🇻 | regional_indicator_symbol_v | 🇼 | regional_indicator_symbol_w | 560 | | 🇽 | regional_indicator_symbol_x | 🇾 | regional_indicator_symbol_y | 561 | | 🇿 | regional_indicator_symbol_z | 🖖 | vulcan_salute | 562 | | 🖕 | middle_finger | 🙂 | slightly_smiling, slight_smile | 563 | | 🤗 | hugging, hug, hugs | 🤔 | thinking, think, thinker | 564 | | 🙄 | eye_roll, rolling_eyes | 🤐 | zipper_mouth, zip_it, sealed_lips, lips_sealed | 565 | | 🤓 | nerd, nerdy | 🙁 | slightly_frowning | 566 | | 🙃 | upside_down, flipped_face | 🤒 | sick, ill, thermometer_face | 567 | | 🤕 | injured, head_bandage, head_bandaged, bandaged | 🤑 | money_mouth, money_face | 568 | | 🕵 | detective, sleuth, private_eye, spy | 🗣 | speaking_head_in_silhouette | 569 | | 🕴 | hovering_man, levitating_man | 🤘 | horns_sign, rock_on, heavy_metal, devil_fingers | 570 | | 🖐 | raised_hand_with_fingers_splayed, splayed_hand | 👁 | eye | 571 | | 🕳 | hole | 🗯 | right_anger_bubble, zig_zag_bubble | 572 | | 🕶 | dark_sunglasses | 🛍 | shopping_bags | 573 | | 📿 | prayer_beads, dhikr_beads, rosary_beads | 🤖 | robot_face, bot_face | 574 | | 🦁 | lion_face, cute_lion, timid_lion | 🦄 | unicorn_face | 575 | | 🐿 | chipmunk, squirrel | 🦃 | turkey | 576 | | 🕊 | dove, dove_peace | 🦀 | crab | 577 | | 🕷 | spider | 🕸 | spider_web, cobweb | 578 | | 🦂 | scorpion | 🏵 | rosette | 579 | | 🌶 | hot_pepper, chili_pepper, spice, spicy | 🧀 | cheese | 580 | | 🌭 | hot_dog | 🌮 | taco | 581 | | 🌯 | burrito, wrap | 🍿 | popcorn | 582 | | 🍾 | champagne, sparkling_wine | 🍽 | fork_knife_plate | 583 | | 🏺 | amphora, jar, vase | 🗺 | world_map | 584 | | 🏔 | snow_capped_mountain, mont_fuji | 🏕 | camping, campsite | 585 | | 🏖 | breach | 🏜 | desert | 586 | | 🏝 | desert_island | 🏞 | national_park | 587 | | 🏟 | stadium | 🏛 | classical_building | 588 | | 🏗 | building_construction, crane | 🏘 | house_buildings, multiple_houses | 589 | | 🏙 | cityscape | 🏚 | derelict_house, old_house, abandoned_house | 590 | | 🛐 | worship_building, worship_place, religious_building, religious_place | 🕋 | kaaba, mecca | 591 | | 🕌 | mosque, minaret, domed_roof | 🕍 | synagogue, temple, jewish | 592 | | 🖼 | picture_frame, painting, gallery | 🛢 | oil_drum | 593 | | 🛣 | motorway, highway, road, interstate, freeway | 🛤 | railway_track | 594 | | 🛳 | passenger_ship | 🛥 | motor_boat | 595 | | 🛩 | small_airplane | 🛫 | airplane_departure, take_off | 596 | | 🛬 | airplane_arriving, airplane_arrival, landing | 🛰 | satellite | 597 | | 🛎 | bellhop_bell | 🛌 | sleeping_accommodation | 598 | | 🛏 | bed, bedroom | 🛋 | couch_lamp, couch, sofa, lounge | 599 | | 🕰 | mantelpiece_clock | 🌡 | thermometer, hot_weather, temperature | 600 | | 🌤 | white_sun_small_cloud | 🌥 | white_sun_behind_cloud | 601 | | 🌦 | white_sun_behind_cloud_rain | 🌧 | cloud_rain | 602 | | 🌨 | cloud_snow | 🌩 | cloud_lightning | 603 | | 🌪 | cloud_tornado | 🌫 | fog | 604 | | 🌬 | wind_blowing_face, mother_nature, blowing_wind | 🕎 | menorah, candelabrum, chanukiah | 605 | | 🎖 | military_medal, military_decoration | 🎗 | reminder_ribbon, awareness_ribbon | 606 | | 🎞 | film_frames | 🎟 | admission_ticket | 607 | | 🏷 | label | 🏌 | golfer, golf_club | 608 | | 🏋 | weight_lifter | 🏎 | racing_car, formula_one, f1 | 609 | | 🏍 | racing_motorcycle, motorcycle, motorbike | 🏅 | sports_medal, sports_decoration | 610 | | 🏏 | cricket_bat_and_ball, cricket_game | 🏐 | volleyball | 611 | | 🏑 | field_hockey | 🏒 | ice_hockey | 612 | | 🏓 | table_tennis, ping_pong | 🏸 | badminton | 613 | | 🕹 | joystick | 🎙 | studio_microphone | 614 | | 🎚 | level_slider | 🎛 | control_knobs | 615 | | *⃣ | keycap_asterisk, star_keycap | 🖥 | desktop_computer, pc_tower, imac | 616 | | 🖨 | printer | 🖱 | computer_mouse, three_button_mouse | 617 | | 🖲 | trackball | 📽 | film_projector | 618 | | 📸 | camera_flash | 🕯 | candle | 619 | | 🗞 | rolled_up_newspaper, newspaper_delivery | 🗳 | ballot, ballot_box | 620 | | 🖋 | lower_left_fountain_pen | 🖊 | lower_left_ballpoint_pen | 621 | | 🖌 | lower_left_paintbrush | 🖍 | lower_left_crayon | 622 | | 🗂 | card_index_dividers | 🗒 | spiral_note_pad | 623 | | 🗓 | spiral_calendar_pad | 🖇 | linked_paperclips | 624 | | 🗃 | card_file_box | 🗄 | file_cabinet | 625 | | 🗑 | wastebasket | 🗝 | old_key | 626 | | 🛠 | hammer_and_wrench | 🗜 | compression | 627 | | 🗡 | dagger, dagger_knife, knife_weapon | 🛡 | shield | 628 | | 🏹 | bow_and_arrow, bow_arrow, archery | 🏳 | waving_white_flag | 629 | | 🏴 | waving_black_flag | 🕉 | om_symbol, pranava, aumkara, omkara | 630 | | 🗨 | left_speech_bubble | 🤣 | rolling_on_the_floor_laughing, rofl | 631 | | 🤠 | face_with_cowboy_hat, cowboy | 🤡 | clown_face, clown | 632 | | 🤥 | lying_face | 🤤 | drooling_face | 633 | | 🤢 | nauseated_face | 🤧 | sneezing_face | 634 | | 🤴 | prince | 🤶 | mother_christmas | 635 | | 🤵 | man_in_tuxedo | 🤷 | shrug | 636 | | 🤦 | face_palm | 🤰 | pregnant_woman | 637 | | 🕺 | man_dancing | 🤳 | selfie | 638 | | 🤞 | hand_with_index_and_middle_fingers_crossed | 🤙 | call_me_hand | 639 | | 🤛 | left-facing_fist | 🤜 | right-facing_fist | 640 | | 🤚 | raised_back_of_hand | 🤝 | handshake | 641 | | 🖤 | black_heart | 🦍 | gorilla | 642 | | 🦊 | fox_face | 🦌 | deer | 643 | | 🦏 | rhinoceros | 🦇 | bat | 644 | | 🦅 | eagle | 🦆 | duck | 645 | | 🦉 | owl | 🦎 | lizard | 646 | | 🦈 | shark | 🦐 | shrimp | 647 | | 🦑 | squid | 🦋 | butterfly | 648 | | 🥀 | wilted_flower | 🥝 | kiwifruit | 649 | | 🥑 | avocado | 🥔 | potato | 650 | | 🥕 | carrot | 🥒 | cucumber | 651 | | 🥜 | peanuts | 🥐 | croissant | 652 | | 🥖 | baguette_bread | 🥞 | pancakes | 653 | | 🥓 | bacon | 🥙 | stuffed_flatbread | 654 | | 🥚 | egg | 🥘 | shallow_pan_of_food | 655 | | 🥗 | green_salad | 🥛 | glass_of_milk | 656 | | 🥂 | clinking_glasses | 🥃 | tumbler_glass | 657 | | 🥄 | spoon | 🛑 | octagonal_sign, stop_sign | 658 | | 🛴 | scooter | 🛵 | motor_scooter | 659 | | 🛶 | canoe | 🥇 | first_place_medal | 660 | | 🥈 | second_place_medal | 🥉 | third_place_medal | 661 | | 🥊 | boxing_glove | 🥋 | martial_arts_uniform | 662 | | 🤸 | person_doing_cartwheel | 🤼 | wrestlers | 663 | | 🤽 | water_polo | 🤾 | handball | 664 | | 🤺 | fencer | 🥅 | goal_net | 665 | | 🤹 | juggling | 🥁 | drum_with_drumsticks | 666 | | 🛒 | shopping_trolley, shopping_cart | 🤩 | star_struck, excited, star_eyes, starry_eyed, wow_face, face_with_starry_eyes, grinning_face_with_star_eyes | 667 | | 🤪 | zany_face, crazy_eyes, wild, goofy_face, grinning_face_with_one_large_and_one_small_eye | 🤭 | face_with_hand_over_mouth, blushing_face_with_hand_over_mouth, smiling_face_with_smiling_eyes_and_hand_covering_mouth | 668 | | 🤫 | shushing_face, hush, quiet, shh, face_with_finger_covering_closed_lips | 🤨 | face_with_raised_eyebrow, colbert, the_rock, face_with_one_eyebrow_raised | 669 | | 🤮 | face_vomiting, spew, throwing_up, vomit, vomiting_face, face_with_open_mouth_vomiting | 🤯 | exploding_head, mind_blown, shocked_face_with_exploding_head | 670 | | 🧐 | face_with_monocle | 🤬 | face_with_symbols_on_mouth, cursing, cussing, grawlix, swearing, face_with_symbols_over_mouth, serious_face_with_symbols_covering_mouth | 671 | | 🧡 | orange_heart | 🤟 | love_you_gesture, i_love_you_hand_sign | 672 | | 🤲 | palms_up_together, dua, palms_together_facing_up | 🧠 | brain | 673 | | 🧒 | child, gender_neutral_child | 🧑 | person, gender_neutral_adult, gender_neutral_person | 674 | | 🧔 | beard, bearded_man, bearded_person, man_with_beard, person_with_beard | 🧓 | older_person, gender_neutral_older_person, older_adult, gender_neutral_older_adult | 675 | | 🧕 | person_with_headscarf, woman_with_headscarf, hijab | 🤱 | breastfeeding | 676 | | 🧙 | mage, gender_neutral_mage | 🧚 | fairy, gender_neutral_fairy | 677 | | 🧛 | vampire, gender_neutral_vampire | 🧜 | merperson, gender_neutral_merperson | 678 | | 🧝 | elf, gender_neutral_elf | 🧞 | genie, gender_neutral_genie, djinni, jinni | 679 | | 🧟 | zombie, gender_neutral_zombie | 🧖 | person_in_steamy_room, sauna | 680 | | 🧗 | person_climbing, climber, rock_climbing | 🧘 | person_in_lotus_position, yoga, meditation | 681 | | 🦓 | zebra_face, zebra | 🦒 | giraffe_face, giraffe | 682 | | 🦔 | hedgehog | 🦕 | sauropod, brontosaurus, diplodocus, dinosaur | 683 | | 🦖 | trex, t_rex, tyrannosaurus_rex | 🦗 | cricket | 684 | | 🥥 | coconut, cocoanut | 🥦 | broccoli | 685 | | 🥨 | pretzel | 🥩 | cut_of_meat, meat, steak | 686 | | 🥪 | sandwich | 🥣 | bowl_with_spoon, cereal_bowl | 687 | | 🥫 | canned_food, tin_can, can_of_food, tinned_food | 🥟 | dumpling, jiaozi, gyoza, pierogi, empanada, xiaolongbao | 688 | | 🥠 | fortune_cookie | 🥡 | takeout_box, chinese_food_box, oyster_pail | 689 | | 🥧 | pie | 🥤 | cup_with_straw, milkshake, smoothie, soda_pop, soft_drink, to_go_cup | 690 | | 🥢 | chopsticks | 🛸 | flying_saucer, ufo, unidentified_flying_object | 691 | | 🛷 | sled | 🥌 | curling_stone | 692 | | 🧣 | scarf | 🧤 | gloves | 693 | | 🧥 | coat | 🧦 | socks | 694 | | 🧢 | billed_cap, baseball_cap, billed_hat | 🥰 | smiling_face_with_hearts, in_love_face, smiling_face_with_smiling_eyes_and_three_hearts | 695 | | 🥵 | hot_face, overheated_face | 🥶 | cold_face, freezing_face | 696 | | 🥴 | woozy_face, drunk_face, face_with_uneven_eyes_and_wavy_mouth | 🥳 | partying_face, party_face, face_with_party_horn_and_party_hat | 697 | | 🥺 | pleading_face, face_with_pleading_eyes | 🦵 | leg | 698 | | 🦶 | foot | 🦷 | tooth | 699 | | 🦴 | bone | 🦸 | superhero | 700 | | 🦹 | supervillain | 🦝 | raccoon | 701 | | 🦙 | llama, alpaca | 🦛 | hippo, hippopotamus | 702 | | 🦘 | roo, kangaroo | 🦡 | badger | 703 | | 🦢 | swan | 🦚 | peacock | 704 | | 🦜 | parrot | 🦟 | mosquito | 705 | | 🦠 | microbe | 🥭 | mango | 706 | | 🥬 | leafy_green, bok_choy, chinese_cabbage, cos_lettuce, romaine_lettuce, leafy_greens | 🥯 | bagel | 707 | | 🧂 | salt_shaker, salt | 🥮 | moon_cake, mooncake | 708 | | 🦞 | lobster | 🧁 | cupcake, fairy_cake | 709 | | 🧭 | compass | 🧱 | brick, bricks | 710 | | 🛹 | skateboard | 🧳 | lugagge, suitcase | 711 | | 🧨 | firecracker, dynamite | 🧧 | red_envelope, red_gift_envelope, ang_pao, hongbao, lai_see, red_packet | 712 | | 🥎 | softball | 🥏 | flying_disc | 713 | | 🥍 | lacrosse, lacrosse_stick_and_ball | 🧿 | nazar_amulet, evil_eye_talisman, nazar_boncugu | 714 | | 🧩 | jigsaw, puzzle_piece, jigsaw_puzzle_piece | 🧸 | teddy_bear | 715 | | ♟️ | black_chess_pawn, chess_pawn | 🧵 | spool_of_thread, thread | 716 | | 🧶 | ball_of_yarn, yarn | 🥽 | goggles | 717 | | 🥼 | lab_coat | 🥾 | hiking_boot | 718 | | 🥿 | flat_shoe | 🧮 | abacus | 719 | | 🧾 | receipt | 🧰 | toolbox | 720 | | 🧲 | magnet | 🧪 | test_tube | 721 | | 🧫 | petri_dish | 🧬 | dna, dna_double_helix | 722 | | 🧴 | lotion_bottle | 🧷 | safety_pin | 723 | | 🧹 | broom | 🧺 | basket | 724 | | 🧻 | roll_of_paper, toilet_paper | 🧼 | bar_of_soap, soap | 725 | | 🧽 | sponge | 🧯 | fire_extinguisher | 726 | | ♾️ | infinity, permanent_paper_sign | ☺ | relaxed | 727 | | ✨ | sparkles | ✊ | fist | 728 | | ✌ | v | ✋ | hand, raised_hand | 729 | | ☝ | point_up | ❤ | heart | 730 | | ⭐ | star | ☀ | sunny | 731 | | ⛅ | partly_sunny | ☁ | cloud | 732 | | ⚡ | zap | ☔ | umbrella | 733 | | ❄ | snowflake | ⛄ | snowman | 734 | | ☎ | phone, telephone | ⏳ | hourglass_flowing_sand | 735 | | ⌛ | hourglass | ⏰ | alarm_clock | 736 | | ⌚ | watch | ✉ | email, envelope | 737 | | ✂ | scissors | ✒ | black_nib | 738 | | ✏ | pencil2 | ⚽ | soccer | 739 | | ⚾ | baseball | ⛳ | golf | 740 | | ☕ | coffee | ⛪ | church | 741 | | ⛺ | tent | ⛲ | fountain | 742 | | ⛵ | boat, sailboat | ⚓ | anchor | 743 | | ✈ | airplane | ⚠ | warning | 744 | | ⛽ | fuelpump | ♨ | hotsprings | 745 | | ⬆ | arrow_up | ⬇ | arrow_down | 746 | | ⬅ | arrow_left | ➡ | arrow_right | 747 | | ↗ | arrow_upper_right | ↖ | arrow_upper_left | 748 | | ↘ | arrow_lower_right | ↙ | arrow_lower_left | 749 | | ↔ | left_right_arrow | ↕ | arrow_up_down | 750 | | ◀ | arrow_backward | ▶ | arrow_forward | 751 | | ↩ | leftwards_arrow_with_hook | ↪ | arrow_right_hook | 752 | | ℹ | information_source | ⏪ | rewind | 753 | | ⏩ | fast_forward | ⏫ | arrow_double_up | 754 | | ⏬ | arrow_double_down | ⤵ | arrow_heading_down | 755 | | ⤴ | arrow_heading_up | ♿ | wheelchair | 756 | | Ⓜ | m | ㊙ | secret | 757 | | ㊗ | congratulations | ⛔ | no_entry | 758 | | ✳ | eight_spoked_asterisk | ❇ | sparkle | 759 | | ❎ | negative_squared_cross_mark | ✅ | white_check_mark | 760 | | ✴ | eight_pointed_black_star | ➿ | loop | 761 | | ♻ | recycle | ♈ | aries | 762 | | ♉ | taurus | ♊ | gemini | 763 | | ♋ | cancer | ♌ | leo | 764 | | ♍ | virgo | ♎ | libra | 765 | | ♏ | scorpius | ♐ | sagittarius | 766 | | ♑ | capricorn | ♒ | aquarius | 767 | | ♓ | pisces | ⛎ | ophiuchus | 768 | | © | copyright | ® | registered | 769 | | ™ | tm | ❌ | x | 770 | | ‼ | bangbang | ⁉ | interrobang | 771 | | ❗ | exclamation, heavy_exclamation_mark | ❓ | question | 772 | | ❕ | grey_exclamation | ❔ | grey_question | 773 | | ⭕ | o | ✖ | heavy_multiplication_x | 774 | | ➕ | heavy_plus_sign | ➖ | heavy_minus_sign | 775 | | ➗ | heavy_division_sign | ♠ | spades | 776 | | ♥ | hearts | ♣ | clubs | 777 | | ♦ | diamonds | ✔ | heavy_check_mark | 778 | | ☑ | ballot_box_with_check | ➰ | curly_loop | 779 | | 〰 | wavy_dash | 〽 | part_alternation_mark | 780 | | ◼ | black_medium_square | ◻ | white_medium_square | 781 | | ◾ | black_medium_small_square | ◽ | white_medium_small_square | 782 | | ▪ | black_small_square | ▫ | white_small_square | 783 | | ⚫ | black_circle | ⚪ | white_circle | 784 | | ⬜ | white_large_square | ⬛ | black_large_square | 785 | | ☹ | frowning_face | ⛑ | helmet_white_cross | 786 | | ✍ | writing, writing_hand | ❣ | exclamation_heart | 787 | | ☠ | skull_crossbones | ☘ | shamrock, st_patrick | 788 | | ⛰ | mountain | ⛴ | ferry | 789 | | ⏱ | stopwatch | ⏲ | timer_clock | 790 | | ⛈ | thunder_cloud_rain | ☂ | open_umbrella | 791 | | ⛱ | planted_umbrella, umbrella_on_ground | ☃ | snowman_with_snow, snowing_snowman | 792 | | ☄ | comet, light_beam, blue_beam | ⛸ | ice_skate, ice_skating | 793 | | ⛷ | skier | ⛹ | person_with_ball | 794 | | ⏭ | black_right_pointing_double_triangle_with_vertical_bar | ⏯ | black_right_pointing_triangle_with_double_vertical_bar | 795 | | ⏮ | black_left_pointing_double_triangle_with_vertical_bar | ⏸ | double_vertical_bar | 796 | | ⏹ | black_square_for_stop | ⏺ | black_circle_for_record | 797 | | ⌨ | keyboard | ⛏ | pick | 798 | | ⚒ | hammer_and_pick | ⚙ | gear | 799 | | ⚗ | alembic | ⚖ | scales, scales_of_justice | 800 | | ⛓ | chains | ⚔ | crossed_swords | 801 | | ⚰ | coffin, funeral, casket | ⚱ | funeral_urn | 802 | | ⚜ | fleur_de_lis, scouts | ⚛ | atom, atom_symbol | 803 | | ✡ | star_of_david | ☸ | wheel_of_dharma | 804 | | ☯ | yin_yang | ✝ | latin_cross, christian_cross | 805 | | ☦ | orthodox_cross | ⛩ | shinto_shrine, kami_no_michi | 806 | | ☪ | star_and_crescent, star_crescent | ☮ | peace_symbol, peace_sign | 807 | | ☢ | radioactive, radioactive_symbol, radioactive_sign | ☣ | biohazard, biohazard_symbol, biohazard_sign | 808 | | ⚕ | medical_symbol, staff_of_aesculapius | 809 | 810 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-present Vincent DURMONT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # emoji-java 2 | 3 | [![Build Status](https://travis-ci.org/vdurmont/emoji-java.svg?branch=master)](https://travis-ci.org/vdurmont/emoji-java) 4 | [![Coverage Status](https://img.shields.io/coveralls/vdurmont/emoji-java.svg)](https://coveralls.io/r/vdurmont/emoji-java?branch=master) 5 | [![License Info](http://img.shields.io/badge/license-The%20MIT%20License-brightgreen.svg)](https://github.com/vdurmont/emoji-java/blob/master/LICENSE.md) 6 | 7 | _The missing emoji library for java._ 8 | 9 | **emoji-java** is a lightweight java library that helps you use Emojis in your java applications. 10 | 11 | ## How to get it? 12 | 13 | ##### Via Maven: 14 | 15 | ```xml 16 | 17 | com.vdurmont 18 | emoji-java 19 | 5.1.1 20 | 21 | ``` 22 | 23 | You can also download the project, build it with `mvn clean install` and add the generated jar to your buildpath. 24 | 25 | ##### Via Gradle: 26 | 27 | ```gradle 28 | compile 'com.vdurmont:emoji-java:5.1.1' 29 | ``` 30 | 31 | ##### Via Direct Download: 32 | 33 | - Use [releases](https://github.com/vdurmont/emoji-java/releases) tab to download the jar directly. 34 | - Download JSON-java dependency from http://mvnrepository.com/artifact/org.json/json. 35 | 36 | ## How to use it? 37 | 38 | ### EmojiManager 39 | 40 | The `EmojiManager` provides several static methods to search through the emojis database: 41 | 42 | - `getForTag` returns all the emojis for a given tag 43 | - `getForAlias` returns the emoji for an alias 44 | - `getAll` returns all the emojis 45 | - `isEmoji` checks if a string is an emoji 46 | - `containsEmoji` checks if a string contains any emoji 47 | 48 | You can also query the metadata: 49 | 50 | - `getAllTags` returns the available tags 51 | 52 | Or get everything: 53 | 54 | - `getAll` returns all the emojis 55 | 56 | ### Emoji model 57 | 58 | An `Emoji` is a POJO (plain old java object), which provides the following methods: 59 | 60 | - `getUnicode` returns the unicode representation of the emoji 61 | - `getUnicode(Fitzpatrick)` returns the unicode representation of the emoji with the provided Fitzpatrick modifier. If the emoji doesn't support the Fitzpatrick modifiers, this method will throw an `UnsupportedOperationException`. If the provided Fitzpatrick is null, this method will return the unicode of the emoji. 62 | - `getDescription` returns the (optional) description of the emoji 63 | - `getAliases` returns a list of aliases for this emoji 64 | - `getTags` returns a list of tags for this emoji 65 | - `getHtmlDecimal` returns an html decimal representation of the emoji 66 | - `getHtmlHexadecimal` returns an html decimal representation of the emoji 67 | - `supportsFitzpatrick` returns true if the emoji supports the Fitzpatrick modifiers, else false 68 | 69 | ### Fitzpatrick modifiers 70 | 71 | Some emojis now support the use of Fitzpatrick modifiers that gives the choice between 5 shades of skin tones: 72 | 73 | | Modifier | Type | 74 | | :------: | -------- | 75 | | 🏻 | type_1_2 | 76 | | 🏼 | type_3 | 77 | | 🏽 | type_4 | 78 | | 🏾 | type_5 | 79 | | 🏿 | type_6 | 80 | 81 | We defined the format of the aliases including a Fitzpatrick modifier as: 82 | 83 | ``` 84 | :ALIAS|TYPE: 85 | ``` 86 | 87 | A few examples: 88 | 89 | ``` 90 | :boy|type_1_2: 91 | :swimmer|type_4: 92 | :santa|type_6: 93 | ``` 94 | 95 | ### EmojiParser 96 | 97 | #### To unicode 98 | 99 | To replace all the aliases and the html representations found in a string by their unicode, use `EmojiParser#parseToUnicode(String)`. 100 | 101 | For example: 102 | 103 | ```java 104 | String str = "An :grinning:awesome :smiley:string 😄with a few :wink:emojis!"; 105 | String result = EmojiParser.parseToUnicode(str); 106 | System.out.println(result); 107 | // Prints: 108 | // "An 😀awesome 😃string 😄with a few 😉emojis!" 109 | ``` 110 | 111 | #### To aliases 112 | 113 | To replace all the emoji's unicodes found in a string by their aliases, use `EmojiParser#parseToAliases(String)`. 114 | 115 | For example: 116 | 117 | ```java 118 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 119 | String result = EmojiParser.parseToAliases(str); 120 | System.out.println(result); 121 | // Prints: 122 | // "An :grinning:awesome :smiley:string with a few :wink:emojis!" 123 | ``` 124 | 125 | By default, the aliases will parse and include any Fitzpatrick modifier that would be provided. If you want to remove or ignore the Fitzpatrick modifiers, use `EmojiParser#parseToAliases(String, FitzpatrickAction)`. Examples: 126 | 127 | ```java 128 | String str = "Here is a boy: \uD83D\uDC66\uD83C\uDFFF!"; 129 | System.out.println(EmojiParser.parseToAliases(str)); 130 | System.out.println(EmojiParser.parseToAliases(str, FitzpatrickAction.PARSE)); 131 | // Prints twice: "Here is a boy: :boy|type_6:!" 132 | System.out.println(EmojiParser.parseToAliases(str, FitzpatrickAction.REMOVE)); 133 | // Prints: "Here is a boy: :boy:!" 134 | System.out.println(EmojiParser.parseToAliases(str, FitzpatrickAction.IGNORE)); 135 | // Prints: "Here is a boy: :boy:🏿!" 136 | ``` 137 | 138 | #### To html 139 | 140 | To replace all the emoji's unicodes found in a string by their html representation, use `EmojiParser#parseToHtmlDecimal(String)` or `EmojiParser#parseToHtmlHexadecimal(String)`. 141 | 142 | For example: 143 | 144 | ```java 145 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 146 | 147 | String resultDecimal = EmojiParser.parseToHtmlDecimal(str); 148 | System.out.println(resultDecimal); 149 | // Prints: 150 | // "An 😀awesome 😃string with a few 😉emojis!" 151 | 152 | String resultHexadecimal = EmojiParser.parseToHtmlHexadecimal(str); 153 | System.out.println(resultHexadecimal); 154 | // Prints: 155 | // "An 😀awesome 😃string with a few 😉emojis!" 156 | ``` 157 | 158 | By default, any Fitzpatrick modifier will be removed. If you want to ignore the Fitzpatrick modifiers, use `EmojiParser#parseToAliases(String, FitzpatrickAction)`. Examples: 159 | 160 | ```java 161 | String str = "Here is a boy: \uD83D\uDC66\uD83C\uDFFF!"; 162 | System.out.println(EmojiParser.parseToHtmlDecimal(str)); 163 | System.out.println(EmojiParser.parseToHtmlDecimal(str, FitzpatrickAction.PARSE)); 164 | System.out.println(EmojiParser.parseToHtmlDecimal(str, FitzpatrickAction.REMOVE)); 165 | // Print 3 times: "Here is a boy: 👦!" 166 | System.out.println(EmojiParser.parseToHtmlDecimal(str, FitzpatrickAction.IGNORE)); 167 | // Prints: "Here is a boy: 👦🏿!" 168 | ``` 169 | 170 | The same applies for the methods `EmojiParser#parseToHtmlHexadecimal(String)` and `EmojiParser#parseToHtmlHexadecimal(String, FitzpatrickAction)`. 171 | 172 | #### Remove emojis 173 | 174 | You can easily remove emojis from a string using one of the following methods: 175 | 176 | - `EmojiParser#removeAllEmojis(String)`: removes all the emojis from the String 177 | - `EmojiParser#removeAllEmojisExcept(String, Collection)`: removes all the emojis from the String, except the ones in the Collection 178 | - `EmojiParser#removeEmojis(String, Collection)`: removes the emojis in the Collection from the String 179 | 180 | For example: 181 | 182 | ```java 183 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 184 | Collection collection = new ArrayList(); 185 | collection.add(EmojiManager.getForAlias("wink")); // This is 😉 186 | 187 | System.out.println(EmojiParser.removeAllEmojis(str)); 188 | System.out.println(EmojiParser.removeAllEmojisExcept(str, collection)); 189 | System.out.println(EmojiParser.removeEmojis(str, collection)); 190 | 191 | // Prints: 192 | // "An awesome string with a few emojis!" 193 | // "An awesome string with a few 😉emojis!" 194 | // "An 😀awesome 😃string with a few emojis!" 195 | ``` 196 | 197 | #### Extract Emojis from a string 198 | 199 | You can search a string of mixed emoji/non-emoji characters and have all of the emoji characters returned as a Collection. 200 | 201 | - `EmojiParser#extractEmojis(String)`: returns all emojis as a Collection. This will include duplicates if emojis are present more than once. 202 | 203 | ## Credits 204 | 205 | **emoji-java** originally used the data provided by the [github/gemoji project](https://github.com/github/gemoji). It is still based on it but has evolved since. 206 | 207 | ## Available Emojis 208 | 209 | See a table of the available emojis and their aliases [HERE](./EMOJIS.md). 210 | -------------------------------------------------------------------------------- /charConverter.js: -------------------------------------------------------------------------------- 1 | // Script to convert a JSON file with "character" emojis to a JSON file with "source code" emojis 2 | // This was probably a one-time thing but I'll commit the code in case it is useful in the future. 3 | // 4 | // Usage: `node charConverter.js` 5 | 6 | const fs = require('fs'); 7 | const path = './src/main/resources/emojis.json'; 8 | const f = fs.readFileSync(path, 'utf8'); 9 | const json = JSON.parse(f); 10 | 11 | const newJson = json.reduce((acc, e) => { 12 | acc.push({ 13 | emojiChar: e.emojiChar, 14 | emoji: convertCharStr2jEsc(e.emojiChar, ''), 15 | description: e.description, 16 | supports_fitzpatrick: e.supports_fitzpatrick || undefined, 17 | supports_gender: e.supports_gender || undefined, 18 | aliases: e.aliases, 19 | tags: e.tags, 20 | }); 21 | return acc; 22 | }, []); 23 | 24 | const newFile = JSON.stringify(newJson, (key, value) => value, 2); 25 | fs.writeFileSync(path, newFile); 26 | 27 | 28 | 29 | /////////////////////////////////////////////////////////////////// 30 | // Following functions copied from https://github.com/r12a/app-conversion/blob/gh-pages/conversionfunctions.js 31 | // http://rishida.net/ 32 | /////////////////////////////////////////////////////////////////// 33 | 34 | 35 | 36 | function convertCharStr2jEsc(str, parameters) { 37 | // Converts a string of characters to JavaScript escapes 38 | // str: sequence of Unicode characters 39 | // parameters: a semicolon separated string showing ids for checkboxes that are turned on 40 | var highsurrogate = 0; 41 | var suppCP; 42 | var pad; 43 | var n = 0; 44 | var pars = parameters.split(';'); 45 | var outputString = ''; 46 | for (var i = 0; i < str.length; i++) { 47 | var cc = str.charCodeAt(i); 48 | if (cc < 0 || cc > 0xffff) { 49 | outputString += 50 | '!Error in convertCharStr2UTF16: unexpected charCodeAt result, cc=' + 51 | cc + 52 | '!'; 53 | } 54 | if (highsurrogate != 0) { 55 | // this is a supp char, and cc contains the low surrogate 56 | if (0xdc00 <= cc && cc <= 0xdfff) { 57 | suppCP = 0x10000 + ((highsurrogate - 0xd800) << 10) + (cc - 0xdc00); 58 | if (parameters.match(/cstyleSC/)) { 59 | pad = suppCP.toString(16); 60 | while (pad.length < 8) { 61 | pad = '0' + pad; 62 | } 63 | outputString += '\\U' + pad; 64 | } else if (parameters.match(/es6styleSC/)) { 65 | pad = suppCP.toString(16).toUpperCase(); 66 | outputString += '\\u{' + pad + '}'; 67 | } else { 68 | suppCP -= 0x10000; 69 | outputString += 70 | '\\u' + 71 | dec2hex4(0xd800 | (suppCP >> 10)) + 72 | '\\u' + 73 | dec2hex4(0xdc00 | (suppCP & 0x3ff)); 74 | } 75 | highsurrogate = 0; 76 | continue; 77 | } else { 78 | outputString += 79 | 'Error in convertCharStr2UTF16: low surrogate expected, cc=' + 80 | cc + 81 | '!'; 82 | highsurrogate = 0; 83 | } 84 | } 85 | if (0xd800 <= cc && cc <= 0xdbff) { 86 | // start of supplementary character 87 | highsurrogate = cc; 88 | } else { 89 | // this is a BMP character 90 | //outputString += dec2hex(cc) + ' '; 91 | switch (cc) { 92 | case 0: 93 | outputString += '\\0'; 94 | break; 95 | case 8: 96 | outputString += '\\b'; 97 | break; 98 | case 9: 99 | if (parameters.match(/noCR/)) { 100 | outputString += '\\t'; 101 | } else { 102 | outputString += '\t'; 103 | } 104 | break; 105 | case 10: 106 | if (parameters.match(/noCR/)) { 107 | outputString += '\\n'; 108 | } else { 109 | outputString += '\n'; 110 | } 111 | break; 112 | case 13: 113 | if (parameters.match(/noCR/)) { 114 | outputString += '\\r'; 115 | } else { 116 | outputString += '\r'; 117 | } 118 | break; 119 | case 11: 120 | outputString += '\\v'; 121 | break; 122 | case 12: 123 | outputString += '\\f'; 124 | break; 125 | case 34: 126 | if (parameters.match(/noCR/)) { 127 | outputString += '\\"'; 128 | } else { 129 | outputString += '"'; 130 | } 131 | break; 132 | case 39: 133 | if (parameters.match(/noCR/)) { 134 | outputString += "\\'"; 135 | } else { 136 | outputString += "'"; 137 | } 138 | break; 139 | case 92: 140 | outputString += '\\\\'; 141 | break; 142 | default: 143 | if (cc > 0x1f && cc < 0x7f) { 144 | outputString += String.fromCharCode(cc); 145 | } else { 146 | pad = cc.toString(16).toUpperCase(); 147 | while (pad.length < 4) { 148 | pad = '0' + pad; 149 | } 150 | outputString += '\\u' + pad; 151 | } 152 | } 153 | } 154 | } 155 | return outputString; 156 | } 157 | 158 | function dec2hex4(textString) { 159 | var hexequiv = new Array( 160 | '0', 161 | '1', 162 | '2', 163 | '3', 164 | '4', 165 | '5', 166 | '6', 167 | '7', 168 | '8', 169 | '9', 170 | 'A', 171 | 'B', 172 | 'C', 173 | 'D', 174 | 'E', 175 | 'F' 176 | ); 177 | return ( 178 | hexequiv[(textString >> 12) & 0xf] + 179 | hexequiv[(textString >> 8) & 0xf] + 180 | hexequiv[(textString >> 4) & 0xf] + 181 | hexequiv[textString & 0xf] 182 | ); 183 | } 184 | -------------------------------------------------------------------------------- /emoji-table-generator/README.md: -------------------------------------------------------------------------------- 1 | # emoji-table-genrator 2 | 3 | This is just a "quick'n'dirty" project to generate a markdown table with all the emojis. 4 | 5 | It is used for the table in the top level README :) 6 | 7 | 8 | Run with: 9 | 10 | ``` 11 | mvn exec:java -Dexec.mainClass="com.vdurmont.emoji.TableGenerator" 12 | ``` -------------------------------------------------------------------------------- /emoji-table-generator/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.vdurmont 6 | emoji-table-generator 7 | 1.0.0-SNAPSHOT 8 | jar 9 | 10 | emoji-table-generator 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | com.vdurmont 20 | emoji-java 21 | 5.1.1 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /emoji-table-generator/src/main/java/com/vdurmont/emoji/TableGenerator.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import java.io.FileWriter; 4 | import java.io.IOException; 5 | 6 | /** 7 | * This app generate the emoji table in the README ;) 8 | *

9 | * Run with: 10 | * mvn exec:java -Dexec.mainClass="com.vdurmont.emoji.TableGenerator" 11 | */ 12 | public class TableGenerator { 13 | public static void main(String[] args) throws IOException { 14 | StringBuilder sb = new StringBuilder(); 15 | 16 | // Table header 17 | sb.append("| Emoji | Aliases | Emoji | Aliases |\n"); 18 | sb.append("| :---: | ------- | :---: | ------- |\n"); 19 | 20 | // Emojis! 21 | int i = 0; 22 | for (Emoji emoji : EmojiManager.getAll()) { 23 | String aliases = getAliases(emoji); 24 | 25 | if (i % 2 == 0) { 26 | sb.append("| ") 27 | .append(emoji.getUnicode()) 28 | .append(" | ") 29 | .append(aliases) 30 | .append(" |"); 31 | } else { 32 | sb.append(" ") 33 | .append(emoji.getUnicode()) 34 | .append(" | ") 35 | .append(aliases) 36 | .append(" |\n"); 37 | } 38 | 39 | i++; 40 | } 41 | 42 | // Output! 43 | if (args.length > 0) { 44 | String path = args[0]; 45 | FileWriter writer = new FileWriter(path); 46 | writer.write(sb.toString()); 47 | System.out.println("Written on " + path); 48 | } else { 49 | System.out.println(sb.toString()); 50 | } 51 | } 52 | 53 | private static String getAliases(Emoji emoji) { 54 | StringBuilder result = new StringBuilder(); 55 | boolean first = true; 56 | for (String alias : emoji.getAliases()) { 57 | if (first) { 58 | first = false; 59 | } else { 60 | result.append(", "); 61 | } 62 | result.append(alias); 63 | } 64 | 65 | return result.toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.vdurmont 6 | emoji-java 7 | 5.1.1 8 | jar 9 | 10 | emoji-java 11 | https://github.com/vdurmont/emoji-java 12 | The missing emoji library for Java. 13 | 14 | 15 | scm:git:git@github.com:vdurmont/emoji-java.git 16 | scm:git:git@github.com:vdurmont/emoji-java.git 17 | git@github.com:vdurmont/emoji-java.git 18 | 19 | 20 | 21 | 22 | Vincent DURMONT 23 | vdurmont@gmail.com 24 | http://www.vincent-durmont.com 25 | 26 | 27 | 28 | 29 | 30 | The MIT License 31 | http://www.opensource.org/licenses/mit-license.php 32 | repo 33 | 34 | 35 | 36 | 37 | UTF-8 38 | 39 | 40 | 41 | 42 | org.json 43 | json 44 | 20170516 45 | 46 | 47 | 48 | junit 49 | junit 50 | 4.13 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.codehaus.mojo 60 | cobertura-maven-plugin 61 | 2.5.2 62 | 63 | xml 64 | 256m 65 | true 66 | 67 | 68 | 69 | org.eluder.coveralls 70 | coveralls-maven-plugin 71 | 2.2.0 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | release 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-source-plugin 85 | 2.3 86 | 87 | 88 | attach-sources 89 | 90 | jar-no-fork 91 | 92 | 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-javadoc-plugin 98 | 2.9.1 99 | 100 | UTF-8 101 | UTF-8 102 | public 103 | 104 | 105 | 106 | attach-javadocs 107 | 108 | jar 109 | 110 | 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-gpg-plugin 116 | 1.6 117 | 118 | 119 | sign-artifacts 120 | verify 121 | 122 | sign 123 | 124 | 125 | 126 | 127 | 128 | org.sonatype.plugins 129 | nexus-staging-maven-plugin 130 | 1.6.7 131 | true 132 | 133 | ossrh 134 | https://oss.sonatype.org/ 135 | true 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | ossrh 146 | Sonatype Nexus Snapshots 147 | https://oss.sonatype.org/content/repositories/snapshots/ 148 | 149 | 150 | ossrh 151 | Nexus Release Repository 152 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /src/main/java/com/vdurmont/emoji/Emoji.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | /** 8 | * This class represents an emoji.
9 | *
10 | * This object is immutable so it can be used safely in a multithreaded context. 11 | * 12 | * @author Vincent DURMONT [vdurmont@gmail.com] 13 | */ 14 | public class Emoji { 15 | private final String description; 16 | private final boolean supportsFitzpatrick; 17 | private final List aliases; 18 | private final List tags; 19 | private final String unicode; 20 | private final String htmlDec; 21 | private final String htmlHex; 22 | 23 | /** 24 | * Constructor for the Emoji. 25 | * 26 | * @param description The description of the emoji 27 | * @param supportsFitzpatrick Whether the emoji supports Fitzpatrick modifiers 28 | * @param aliases the aliases for this emoji 29 | * @param tags the tags associated with this emoji 30 | * @param bytes the bytes that represent the emoji 31 | */ 32 | protected Emoji( 33 | String description, 34 | boolean supportsFitzpatrick, 35 | List aliases, 36 | List tags, 37 | byte... bytes 38 | ) { 39 | this.description = description; 40 | this.supportsFitzpatrick = supportsFitzpatrick; 41 | this.aliases = Collections.unmodifiableList(aliases); 42 | this.tags = Collections.unmodifiableList(tags); 43 | 44 | int count = 0; 45 | try { 46 | this.unicode = new String(bytes, "UTF-8"); 47 | int stringLength = getUnicode().length(); 48 | String[] pointCodes = new String[stringLength]; 49 | String[] pointCodesHex = new String[stringLength]; 50 | 51 | for (int offset = 0; offset < stringLength; ) { 52 | final int codePoint = getUnicode().codePointAt(offset); 53 | 54 | pointCodes[count] = String.format("&#%d;", codePoint); 55 | pointCodesHex[count++] = String.format("&#x%x;", codePoint); 56 | 57 | offset += Character.charCount(codePoint); 58 | } 59 | this.htmlDec = stringJoin(pointCodes, count); 60 | this.htmlHex = stringJoin(pointCodesHex, count); 61 | } catch (UnsupportedEncodingException e) { 62 | throw new RuntimeException(e); 63 | } 64 | } 65 | 66 | /** 67 | * Method to replace String.join, since it was only introduced in java8 68 | * @param array the array to be concatenated 69 | * @return concatenated String 70 | */ 71 | private String stringJoin(String[] array, int count){ 72 | String joined = ""; 73 | for(int i = 0; i < count; i++) 74 | joined += array[i]; 75 | return joined; 76 | } 77 | 78 | /** 79 | * Returns the description of the emoji 80 | * 81 | * @return the description 82 | */ 83 | public String getDescription() { 84 | return this.description; 85 | } 86 | 87 | /** 88 | * Returns wether the emoji supports the Fitzpatrick modifiers or not 89 | * 90 | * @return true if the emoji supports the Fitzpatrick modifiers 91 | */ 92 | public boolean supportsFitzpatrick() { 93 | return this.supportsFitzpatrick; 94 | } 95 | 96 | /** 97 | * Returns the aliases of the emoji 98 | * 99 | * @return the aliases (unmodifiable) 100 | */ 101 | public List getAliases() { 102 | return this.aliases; 103 | } 104 | 105 | /** 106 | * Returns the tags of the emoji 107 | * 108 | * @return the tags (unmodifiable) 109 | */ 110 | public List getTags() { 111 | return this.tags; 112 | } 113 | 114 | /** 115 | * Returns the unicode representation of the emoji 116 | * 117 | * @return the unicode representation 118 | */ 119 | public String getUnicode() { 120 | return this.unicode; 121 | } 122 | 123 | /** 124 | * Returns the unicode representation of the emoji associated with the 125 | * provided Fitzpatrick modifier.
126 | * If the modifier is null, then the result is similar to 127 | * {@link Emoji#getUnicode()} 128 | * 129 | * @param fitzpatrick the fitzpatrick modifier or null 130 | * 131 | * @return the unicode representation 132 | * @throws UnsupportedOperationException if the emoji doesn't support the 133 | * Fitzpatrick modifiers 134 | */ 135 | public String getUnicode(Fitzpatrick fitzpatrick) { 136 | if (!this.supportsFitzpatrick()) { 137 | throw new UnsupportedOperationException( 138 | "Cannot get the unicode with a fitzpatrick modifier, " + 139 | "the emoji doesn't support fitzpatrick." 140 | ); 141 | } else if (fitzpatrick == null) { 142 | return this.getUnicode(); 143 | } 144 | return this.getUnicode() + fitzpatrick.unicode; 145 | } 146 | 147 | /** 148 | * Returns the HTML decimal representation of the emoji 149 | * 150 | * @return the HTML decimal representation 151 | */ 152 | public String getHtmlDecimal() { 153 | return this.htmlDec; 154 | } 155 | 156 | /** 157 | * @deprecated identical to {@link #getHtmlHexadecimal()} for 158 | * backwards-compatibility. Use that instead. 159 | * 160 | * @return the HTML hexadecimal representation 161 | */ 162 | public String getHtmlHexidecimal() { 163 | return this.getHtmlHexadecimal(); 164 | } 165 | 166 | /** 167 | * Returns the HTML hexadecimal representation of the emoji 168 | * 169 | * @return the HTML hexadecimal representation 170 | */ 171 | public String getHtmlHexadecimal() { 172 | return this.htmlHex; 173 | } 174 | 175 | @Override 176 | public boolean equals(Object other) { 177 | return !(other == null || !(other instanceof Emoji)) && 178 | ((Emoji) other).getUnicode().equals(getUnicode()); 179 | } 180 | 181 | @Override 182 | public int hashCode() { 183 | return unicode.hashCode(); 184 | } 185 | 186 | /** 187 | * Returns the String representation of the Emoji object.
188 | *
189 | * Example:
190 | * Emoji { 191 | * description='smiling face with open mouth and smiling eyes', 192 | * supportsFitzpatrick=false, 193 | * aliases=[smile], 194 | * tags=[happy, joy, pleased], 195 | * unicode='😄', 196 | * htmlDec='&#128516;', 197 | * htmlHex='&#x1f604;' 198 | * } 199 | * 200 | * @return the string representation 201 | */ 202 | @Override 203 | public String toString() { 204 | return "Emoji{" + 205 | "description='" + description + '\'' + 206 | ", supportsFitzpatrick=" + supportsFitzpatrick + 207 | ", aliases=" + aliases + 208 | ", tags=" + tags + 209 | ", unicode='" + unicode + '\'' + 210 | ", htmlDec='" + htmlDec + '\'' + 211 | ", htmlHex='" + htmlHex + '\'' + 212 | '}'; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/main/java/com/vdurmont/emoji/EmojiLoader.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.UnsupportedEncodingException; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Scanner; 14 | 15 | /** 16 | * Loads the emojis from a JSON database. 17 | * 18 | * @author Vincent DURMONT [vdurmont@gmail.com] 19 | */ 20 | public class EmojiLoader { 21 | /** 22 | * No need for a constructor, all the methods are static. 23 | */ 24 | private EmojiLoader() {} 25 | 26 | /** 27 | * Loads a JSONArray of emojis from an InputStream, parses it and returns the 28 | * associated list of {@link com.vdurmont.emoji.Emoji}s 29 | * 30 | * @param stream the stream of the JSONArray 31 | * 32 | * @return the list of {@link com.vdurmont.emoji.Emoji}s 33 | * @throws IOException if an error occurs while reading the stream or parsing 34 | * the JSONArray 35 | */ 36 | public static List loadEmojis(InputStream stream) throws IOException { 37 | JSONArray emojisJSON = new JSONArray(inputStreamToString(stream)); 38 | List emojis = new ArrayList(emojisJSON.length()); 39 | for (int i = 0; i < emojisJSON.length(); i++) { 40 | Emoji emoji = buildEmojiFromJSON(emojisJSON.getJSONObject(i)); 41 | if (emoji != null) { 42 | emojis.add(emoji); 43 | } 44 | } 45 | return emojis; 46 | } 47 | 48 | private static String inputStreamToString( 49 | InputStream stream 50 | ) throws IOException { 51 | StringBuilder sb = new StringBuilder(); 52 | InputStreamReader isr = new InputStreamReader(stream, "UTF-8"); 53 | BufferedReader br = new BufferedReader(isr); 54 | String read; 55 | while((read = br.readLine()) != null) { 56 | sb.append(read); 57 | } 58 | br.close(); 59 | return sb.toString(); 60 | } 61 | 62 | protected static Emoji buildEmojiFromJSON( 63 | JSONObject json 64 | ) throws UnsupportedEncodingException { 65 | if (!json.has("emoji")) { 66 | return null; 67 | } 68 | 69 | byte[] bytes = json.getString("emoji").getBytes("UTF-8"); 70 | String description = null; 71 | if (json.has("description")) { 72 | description = json.getString("description"); 73 | } 74 | boolean supportsFitzpatrick = false; 75 | if (json.has("supports_fitzpatrick")) { 76 | supportsFitzpatrick = json.getBoolean("supports_fitzpatrick"); 77 | } 78 | List aliases = jsonArrayToStringList(json.getJSONArray("aliases")); 79 | List tags = jsonArrayToStringList(json.getJSONArray("tags")); 80 | return new Emoji(description, supportsFitzpatrick, aliases, tags, bytes); 81 | } 82 | 83 | private static List jsonArrayToStringList(JSONArray array) { 84 | List strings = new ArrayList(array.length()); 85 | for (int i = 0; i < array.length(); i++) { 86 | strings.add(array.getString(i)); 87 | } 88 | return strings; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/vdurmont/emoji/EmojiManager.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | /** 15 | * Holds the loaded emojis and provides search functions. 16 | * 17 | * @author Vincent DURMONT [vdurmont@gmail.com] 18 | */ 19 | public class EmojiManager { 20 | private static final String PATH = "/emojis.json"; 21 | private static final Map EMOJIS_BY_ALIAS = 22 | new HashMap(); 23 | private static final Map> EMOJIS_BY_TAG = 24 | new HashMap>(); 25 | private static final List ALL_EMOJIS; 26 | static final EmojiTrie EMOJI_TRIE; 27 | 28 | static { 29 | try { 30 | InputStream stream = EmojiLoader.class.getResourceAsStream(PATH); 31 | List emojis = EmojiLoader.loadEmojis(stream); 32 | ALL_EMOJIS = emojis; 33 | for (Emoji emoji : emojis) { 34 | for (String tag : emoji.getTags()) { 35 | if (EMOJIS_BY_TAG.get(tag) == null) { 36 | EMOJIS_BY_TAG.put(tag, new HashSet()); 37 | } 38 | EMOJIS_BY_TAG.get(tag).add(emoji); 39 | } 40 | for (String alias : emoji.getAliases()) { 41 | EMOJIS_BY_ALIAS.put(alias, emoji); 42 | } 43 | } 44 | 45 | EMOJI_TRIE = new EmojiTrie(emojis); 46 | Collections.sort(ALL_EMOJIS, new Comparator() { 47 | public int compare(Emoji e1, Emoji e2) { 48 | return e2.getUnicode().length() - e1.getUnicode().length(); 49 | } 50 | }); 51 | stream.close(); 52 | } catch (IOException e) { 53 | throw new RuntimeException(e); 54 | } 55 | } 56 | 57 | /** 58 | * No need for a constructor, all the methods are static. 59 | */ 60 | private EmojiManager() {} 61 | 62 | /** 63 | * Returns all the {@link com.vdurmont.emoji.Emoji}s for a given tag. 64 | * 65 | * @param tag the tag 66 | * 67 | * @return the associated {@link com.vdurmont.emoji.Emoji}s, null if the tag 68 | * is unknown 69 | */ 70 | public static Set getForTag(String tag) { 71 | if (tag == null) { 72 | return null; 73 | } 74 | return EMOJIS_BY_TAG.get(tag); 75 | } 76 | 77 | /** 78 | * Returns the {@link com.vdurmont.emoji.Emoji} for a given alias. 79 | * 80 | * @param alias the alias 81 | * 82 | * @return the associated {@link com.vdurmont.emoji.Emoji}, null if the alias 83 | * is unknown 84 | */ 85 | public static Emoji getForAlias(String alias) { 86 | if (alias == null || alias.isEmpty()) { 87 | return null; 88 | } 89 | return EMOJIS_BY_ALIAS.get(trimAlias(alias)); 90 | } 91 | 92 | private static String trimAlias(String alias) { 93 | int len = alias.length(); 94 | return alias.substring( 95 | alias.charAt(0) == ':' ? 1 : 0, 96 | alias.charAt(len - 1) == ':' ? len - 1 : len); 97 | } 98 | 99 | 100 | /** 101 | * Returns the {@link com.vdurmont.emoji.Emoji} for a given unicode. 102 | * 103 | * @param unicode the the unicode 104 | * 105 | * @return the associated {@link com.vdurmont.emoji.Emoji}, null if the 106 | * unicode is unknown 107 | */ 108 | public static Emoji getByUnicode(String unicode) { 109 | if (unicode == null) { 110 | return null; 111 | } 112 | return EMOJI_TRIE.getEmoji(unicode); 113 | } 114 | 115 | /** 116 | * Returns all the {@link com.vdurmont.emoji.Emoji}s 117 | * 118 | * @return all the {@link com.vdurmont.emoji.Emoji}s 119 | */ 120 | public static Collection getAll() { 121 | return ALL_EMOJIS; 122 | } 123 | 124 | /** 125 | * Tests if a given String is an emoji. 126 | * 127 | * @param string the string to test 128 | * 129 | * @return true if the string is an emoji's unicode, false else 130 | */ 131 | public static boolean isEmoji(String string) { 132 | if (string == null) return false; 133 | 134 | EmojiParser.UnicodeCandidate unicodeCandidate = EmojiParser.getNextUnicodeCandidate(string.toCharArray(), 0); 135 | return unicodeCandidate != null && 136 | unicodeCandidate.getEmojiStartIndex() == 0 && 137 | unicodeCandidate.getFitzpatrickEndIndex() == string.length(); 138 | } 139 | 140 | /** 141 | * Tests if a given String contains an emoji. 142 | * 143 | * @param string the string to test 144 | * 145 | * @return true if the string contains an emoji's unicode, false otherwise 146 | */ 147 | public static boolean containsEmoji(String string) { 148 | if (string == null) return false; 149 | 150 | return EmojiParser.getNextUnicodeCandidate(string.toCharArray(), 0) != null; 151 | } 152 | 153 | /** 154 | * Tests if a given String only contains emojis. 155 | * 156 | * @param string the string to test 157 | * 158 | * @return true if the string only contains emojis, false else 159 | */ 160 | public static boolean isOnlyEmojis(String string) { 161 | return string != null && EmojiParser.removeAllEmojis(string).isEmpty(); 162 | } 163 | 164 | /** 165 | * Checks if sequence of chars contain an emoji. 166 | * @param sequence Sequence of char that may contain emoji in full or 167 | * partially. 168 | * 169 | * @return 170 | * <li> 171 | * Matches.EXACTLY if char sequence in its entirety is an emoji 172 | * </li> 173 | * <li> 174 | * Matches.POSSIBLY if char sequence matches prefix of an emoji 175 | * </li> 176 | * <li> 177 | * Matches.IMPOSSIBLE if char sequence matches no emoji or prefix of an 178 | * emoji 179 | * </li> 180 | */ 181 | public static EmojiTrie.Matches isEmoji(char[] sequence) { 182 | return EMOJI_TRIE.isEmoji(sequence); 183 | } 184 | 185 | /** 186 | * Returns all the tags in the database 187 | * 188 | * @return the tags 189 | */ 190 | public static Collection getAllTags() { 191 | return EMOJIS_BY_TAG.keySet(); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/main/java/com/vdurmont/emoji/EmojiParser.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | /** 8 | * Provides methods to parse strings with emojis. 9 | * 10 | * @author Vincent DURMONT [vdurmont@gmail.com] 11 | */ 12 | public class EmojiParser { 13 | 14 | /** 15 | * See {@link #parseToAliases(String, FitzpatrickAction)} with the action 16 | * "PARSE" 17 | * 18 | * @param input the string to parse 19 | * 20 | * @return the string with the emojis replaced by their alias. 21 | */ 22 | public static String parseToAliases(String input) { 23 | return parseToAliases(input, FitzpatrickAction.PARSE); 24 | } 25 | 26 | /** 27 | * Replaces the emoji's unicode occurrences by one of their alias 28 | * (between 2 ':').
29 | * Example: 😄 will be replaced by :smile:
30 | *
31 | * When a fitzpatrick modifier is present with a PARSE action, a "|" will be 32 | * appendend to the alias, with the fitzpatrick type.
33 | * Example: 👦🏿 will be replaced by 34 | * :boy|type_6:
35 | * The fitzpatrick types are: type_1_2, type_3, type_4, type_5, type_6
36 | *
37 | * When a fitzpatrick modifier is present with a REMOVE action, the modifier 38 | * will be deleted.
39 | * Example: 👦🏿 will be replaced by :boy:
40 | *
41 | * When a fitzpatrick modifier is present with a IGNORE action, the modifier 42 | * will be ignored.
43 | * Example: 👦🏿 will be replaced by :boy:🏿
44 | * 45 | * @param input the string to parse 46 | * @param fitzpatrickAction the action to apply for the fitzpatrick modifiers 47 | * 48 | * @return the string with the emojis replaced by their alias. 49 | */ 50 | public static String parseToAliases( 51 | String input, 52 | final FitzpatrickAction fitzpatrickAction 53 | ) { 54 | EmojiTransformer emojiTransformer = new EmojiTransformer() { 55 | public String transform(UnicodeCandidate unicodeCandidate) { 56 | switch (fitzpatrickAction) { 57 | default: 58 | case PARSE: 59 | if (unicodeCandidate.hasFitzpatrick()) { 60 | return ":" + 61 | unicodeCandidate.getEmoji().getAliases().get(0) + 62 | "|" + 63 | unicodeCandidate.getFitzpatrickType() + 64 | ":"; 65 | } 66 | case REMOVE: 67 | return ":" + 68 | unicodeCandidate.getEmoji().getAliases().get(0) + 69 | ":"; 70 | case IGNORE: 71 | return ":" + 72 | unicodeCandidate.getEmoji().getAliases().get(0) + 73 | ":" + 74 | unicodeCandidate.getFitzpatrickUnicode(); 75 | } 76 | } 77 | }; 78 | 79 | return parseFromUnicode(input, emojiTransformer); 80 | } 81 | 82 | /** 83 | * Replace all emojis with character 84 | * 85 | * @param str the string to process 86 | * @param replacementString replacement the string that will replace all the emojis 87 | * @return the string with replaced character 88 | */ 89 | public static String replaceAllEmojis(String str, final String replacementString) { 90 | EmojiParser.EmojiTransformer emojiTransformer = new EmojiParser.EmojiTransformer() { 91 | public String transform(EmojiParser.UnicodeCandidate unicodeCandidate) { 92 | return replacementString; 93 | } 94 | }; 95 | 96 | return parseFromUnicode(str, emojiTransformer); 97 | } 98 | 99 | 100 | /** 101 | * Replaces the emoji's aliases (between 2 ':') occurrences and the html 102 | * representations by their unicode.
103 | * Examples:
104 | * :smile: will be replaced by 😄
105 | * &#128516; will be replaced by 😄
106 | * :boy|type_6: will be replaced by 👦🏿 107 | * 108 | * @param input the string to parse 109 | * 110 | * @return the string with the aliases and html representations replaced by 111 | * their unicode. 112 | */ 113 | public static String parseToUnicode(String input) { 114 | StringBuilder sb = new StringBuilder(input.length()); 115 | 116 | for (int last = 0; last < input.length(); last++) { 117 | AliasCandidate alias = getAliasAt(input, last); 118 | if (alias == null) { 119 | alias = getHtmlEncodedEmojiAt(input, last); 120 | } 121 | 122 | if (alias != null) { 123 | sb.append(alias.emoji.getUnicode()); 124 | last = alias.endIndex; 125 | 126 | if (alias.fitzpatrick != null) { 127 | sb.append(alias.fitzpatrick.unicode); 128 | } 129 | } else { 130 | sb.append(input.charAt(last)); 131 | } 132 | } 133 | 134 | return sb.toString(); 135 | } 136 | 137 | /** Finds the alias in the given string starting at the given point, null otherwise */ 138 | protected static AliasCandidate getAliasAt(String input, int start) { 139 | if (input.length() < start + 2 || input.charAt(start) != ':') return null; // Aliases start with : 140 | int aliasEnd = input.indexOf(':', start + 2); // Alias must be at least 1 char in length 141 | if (aliasEnd == -1) return null; // No alias end found 142 | 143 | int fitzpatrickStart = input.indexOf('|', start + 2); 144 | if (fitzpatrickStart != -1 && fitzpatrickStart < aliasEnd) { 145 | Emoji emoji = EmojiManager.getForAlias(input.substring(start, fitzpatrickStart)); 146 | if (emoji == null) return null; // Not a valid alias 147 | if (!emoji.supportsFitzpatrick()) return null; // Fitzpatrick was specified, but the emoji does not support it 148 | Fitzpatrick fitzpatrick = Fitzpatrick.fitzpatrickFromType(input.substring(fitzpatrickStart + 1, aliasEnd)); 149 | return new AliasCandidate(emoji, fitzpatrick, start, aliasEnd); 150 | } 151 | 152 | Emoji emoji = EmojiManager.getForAlias(input.substring(start, aliasEnd)); 153 | if (emoji == null) return null; // Not a valid alias 154 | return new AliasCandidate(emoji, null, start, aliasEnd); 155 | } 156 | 157 | /** Finds the HTML encoded emoji in the given string starting at the given point, null otherwise */ 158 | protected static AliasCandidate getHtmlEncodedEmojiAt(String input, int start) { 159 | if (input.length() < start + 4 || input.charAt(start) != '&' || input.charAt(start + 1) != '#') return null; 160 | 161 | Emoji longestEmoji = null; 162 | int longestCodePointEnd = -1; 163 | char[] chars = new char[EmojiManager.EMOJI_TRIE.maxDepth]; 164 | int charsIndex = 0; 165 | int codePointStart = start; 166 | do { 167 | int codePointEnd = input.indexOf(';', codePointStart + 3); // Code point must be at least 1 char in length 168 | if (codePointEnd == -1) break; 169 | 170 | try { 171 | int radix = input.charAt(codePointStart + 2) == 'x' ? 16 : 10; 172 | int codePoint = Integer.parseInt(input.substring(codePointStart + 2 + radix / 16, codePointEnd), radix); 173 | charsIndex += Character.toChars(codePoint, chars, charsIndex); 174 | } catch (NumberFormatException e) { 175 | break; 176 | } catch (IllegalArgumentException e) { 177 | break; 178 | } 179 | Emoji foundEmoji = EmojiManager.EMOJI_TRIE.getEmoji(chars, 0, charsIndex); 180 | if (foundEmoji != null) { 181 | longestEmoji = foundEmoji; 182 | longestCodePointEnd = codePointEnd; 183 | } 184 | codePointStart = codePointEnd + 1; 185 | } while (input.length() > codePointStart + 4 && 186 | input.charAt(codePointStart) == '&' && 187 | input.charAt(codePointStart + 1) == '#' && 188 | charsIndex < chars.length && 189 | !EmojiManager.EMOJI_TRIE.isEmoji(chars, 0, charsIndex).impossibleMatch()); 190 | 191 | if (longestEmoji == null) return null; 192 | return new AliasCandidate(longestEmoji, null, start, longestCodePointEnd); 193 | } 194 | 195 | /** 196 | * See {@link #parseToHtmlDecimal(String, FitzpatrickAction)} with the action 197 | * "PARSE" 198 | * 199 | * @param input the string to parse 200 | * 201 | * @return the string with the emojis replaced by their html decimal 202 | * representation. 203 | */ 204 | public static String parseToHtmlDecimal(String input) { 205 | return parseToHtmlDecimal(input, FitzpatrickAction.PARSE); 206 | } 207 | 208 | /** 209 | * Replaces the emoji's unicode occurrences by their html representation.
210 | * Example: 😄 will be replaced by &#128516;
211 | *
212 | * When a fitzpatrick modifier is present with a PARSE or REMOVE action, the 213 | * modifier will be deleted from the string.
214 | * Example: 👦🏿 will be replaced by 215 | * &#128102;
216 | *
217 | * When a fitzpatrick modifier is present with a IGNORE action, the modifier 218 | * will be ignored and will remain in the string.
219 | * Example: 👦🏿 will be replaced by 220 | * &#128102;🏿 221 | * 222 | * @param input the string to parse 223 | * @param fitzpatrickAction the action to apply for the fitzpatrick modifiers 224 | * 225 | * @return the string with the emojis replaced by their html decimal 226 | * representation. 227 | */ 228 | public static String parseToHtmlDecimal( 229 | String input, 230 | final FitzpatrickAction fitzpatrickAction 231 | ) { 232 | EmojiTransformer emojiTransformer = new EmojiTransformer() { 233 | public String transform(UnicodeCandidate unicodeCandidate) { 234 | switch (fitzpatrickAction) { 235 | default: 236 | case PARSE: 237 | case REMOVE: 238 | return unicodeCandidate.getEmoji().getHtmlDecimal(); 239 | case IGNORE: 240 | return unicodeCandidate.getEmoji().getHtmlDecimal() + 241 | unicodeCandidate.getFitzpatrickUnicode(); 242 | } 243 | } 244 | }; 245 | 246 | return parseFromUnicode(input, emojiTransformer); 247 | } 248 | 249 | /** 250 | * See {@link #parseToHtmlHexadecimal(String, FitzpatrickAction)} with the 251 | * action "PARSE" 252 | * 253 | * @param input the string to parse 254 | * 255 | * @return the string with the emojis replaced by their html hex 256 | * representation. 257 | */ 258 | public static String parseToHtmlHexadecimal(String input) { 259 | return parseToHtmlHexadecimal(input, FitzpatrickAction.PARSE); 260 | } 261 | 262 | /** 263 | * Replaces the emoji's unicode occurrences by their html hex 264 | * representation.
265 | * Example: 👦 will be replaced by &#x1f466;
266 | *
267 | * When a fitzpatrick modifier is present with a PARSE or REMOVE action, the 268 | * modifier will be deleted.
269 | * Example: 👦🏿 will be replaced by 270 | * &#x1f466;
271 | *
272 | * When a fitzpatrick modifier is present with a IGNORE action, the modifier 273 | * will be ignored and will remain in the string.
274 | * Example: 👦🏿 will be replaced by 275 | * &#x1f466;🏿 276 | * 277 | * @param input the string to parse 278 | * @param fitzpatrickAction the action to apply for the fitzpatrick modifiers 279 | * 280 | * @return the string with the emojis replaced by their html hex 281 | * representation. 282 | */ 283 | public static String parseToHtmlHexadecimal( 284 | String input, 285 | final FitzpatrickAction fitzpatrickAction 286 | ) { 287 | EmojiTransformer emojiTransformer = new EmojiTransformer() { 288 | public String transform(UnicodeCandidate unicodeCandidate) { 289 | switch (fitzpatrickAction) { 290 | default: 291 | case PARSE: 292 | case REMOVE: 293 | return unicodeCandidate.getEmoji().getHtmlHexadecimal(); 294 | case IGNORE: 295 | return unicodeCandidate.getEmoji().getHtmlHexadecimal() + 296 | unicodeCandidate.getFitzpatrickUnicode(); 297 | } 298 | } 299 | }; 300 | 301 | return parseFromUnicode(input, emojiTransformer); 302 | } 303 | 304 | /** 305 | * Removes all emojis from a String 306 | * 307 | * @param str the string to process 308 | * 309 | * @return the string without any emoji 310 | */ 311 | public static String removeAllEmojis(String str) { 312 | EmojiTransformer emojiTransformer = new EmojiTransformer() { 313 | public String transform(UnicodeCandidate unicodeCandidate) { 314 | return ""; 315 | } 316 | }; 317 | 318 | return parseFromUnicode(str, emojiTransformer); 319 | } 320 | 321 | 322 | /** 323 | * Removes a set of emojis from a String 324 | * 325 | * @param str the string to process 326 | * @param emojisToRemove the emojis to remove from this string 327 | * 328 | * @return the string without the emojis that were removed 329 | */ 330 | public static String removeEmojis( 331 | String str, 332 | final Collection emojisToRemove 333 | ) { 334 | EmojiTransformer emojiTransformer = new EmojiTransformer() { 335 | public String transform(UnicodeCandidate unicodeCandidate) { 336 | if (!emojisToRemove.contains(unicodeCandidate.getEmoji())) { 337 | return unicodeCandidate.getEmoji().getUnicode() + 338 | unicodeCandidate.getFitzpatrickUnicode(); 339 | } 340 | return ""; 341 | } 342 | }; 343 | 344 | return parseFromUnicode(str, emojiTransformer); 345 | } 346 | 347 | /** 348 | * Removes all the emojis in a String except a provided set 349 | * 350 | * @param str the string to process 351 | * @param emojisToKeep the emojis to keep in this string 352 | * 353 | * @return the string without the emojis that were removed 354 | */ 355 | public static String removeAllEmojisExcept( 356 | String str, 357 | final Collection emojisToKeep 358 | ) { 359 | EmojiTransformer emojiTransformer = new EmojiTransformer() { 360 | public String transform(UnicodeCandidate unicodeCandidate) { 361 | if (emojisToKeep.contains(unicodeCandidate.getEmoji())) { 362 | return unicodeCandidate.getEmoji().getUnicode() + 363 | unicodeCandidate.getFitzpatrickUnicode(); 364 | } 365 | return ""; 366 | } 367 | }; 368 | 369 | return parseFromUnicode(str, emojiTransformer); 370 | } 371 | 372 | 373 | /** 374 | * Detects all unicode emojis in input string and replaces them with the 375 | * return value of transformer.transform() 376 | * 377 | * @param input the string to process 378 | * @param transformer emoji transformer to apply to each emoji 379 | * 380 | * @return input string with all emojis transformed 381 | */ 382 | public static String parseFromUnicode( 383 | String input, 384 | EmojiTransformer transformer 385 | ) { 386 | int prev = 0; 387 | StringBuilder sb = new StringBuilder(input.length()); 388 | List replacements = getUnicodeCandidates(input); 389 | for (UnicodeCandidate candidate : replacements) { 390 | sb.append(input, prev, candidate.getEmojiStartIndex()); 391 | 392 | sb.append(transformer.transform(candidate)); 393 | prev = candidate.getFitzpatrickEndIndex(); 394 | } 395 | 396 | return sb.append(input.substring(prev)).toString(); 397 | } 398 | 399 | public static List extractEmojis(String input) { 400 | List emojis = getUnicodeCandidates(input); 401 | List result = new ArrayList(); 402 | for (UnicodeCandidate emoji : emojis) { 403 | if (emoji.getEmoji().supportsFitzpatrick() && emoji.hasFitzpatrick()) { 404 | result.add(emoji.getEmoji().getUnicode(emoji.getFitzpatrick())); 405 | } else { 406 | result.add(emoji.getEmoji().getUnicode()); 407 | } 408 | } 409 | return result; 410 | } 411 | 412 | 413 | /** 414 | * Generates a list UnicodeCandidates found in input string. A 415 | * UnicodeCandidate is created for every unicode emoticon found in input 416 | * string, additionally if Fitzpatrick modifier follows the emoji, it is 417 | * included in UnicodeCandidate. Finally, it contains start and end index of 418 | * unicode emoji itself (WITHOUT Fitzpatrick modifier whether it is there or 419 | * not!). 420 | * 421 | * @param input String to find all unicode emojis in 422 | * @return List of UnicodeCandidates for each unicode emote in text 423 | */ 424 | protected static List getUnicodeCandidates(String input) { 425 | char[] inputCharArray = input.toCharArray(); 426 | List candidates = new ArrayList(); 427 | UnicodeCandidate next; 428 | for (int i = 0; (next = getNextUnicodeCandidate(inputCharArray, i)) != null; i = next.getFitzpatrickEndIndex()) { 429 | candidates.add(next); 430 | } 431 | 432 | return candidates; 433 | } 434 | 435 | /** 436 | * Finds the next UnicodeCandidate after a given starting index 437 | * 438 | * @param chars char array to find UnicodeCandidate in 439 | * @param start starting index for search 440 | * @return the next UnicodeCandidate or null if no UnicodeCandidate is found after start index 441 | */ 442 | protected static UnicodeCandidate getNextUnicodeCandidate(char[] chars, int start) { 443 | for (int i = start; i < chars.length; i++) { 444 | int emojiEnd = getEmojiEndPos(chars, i); 445 | 446 | if (emojiEnd != -1) { 447 | Emoji emoji = EmojiManager.getByUnicode(new String(chars, i, emojiEnd - i)); 448 | String fitzpatrickString = (emojiEnd + 2 <= chars.length) ? 449 | new String(chars, emojiEnd, 2) : 450 | null; 451 | return new UnicodeCandidate( 452 | emoji, 453 | fitzpatrickString, 454 | i 455 | ); 456 | } 457 | } 458 | 459 | return null; 460 | } 461 | 462 | 463 | /** 464 | * Returns end index of a unicode emoji if it is found in text starting at 465 | * index startPos, -1 if not found. 466 | * This returns the longest matching emoji, for example, in 467 | * "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66" 468 | * it will find alias:family_man_woman_boy, NOT alias:man 469 | * 470 | * @param text the current text where we are looking for an emoji 471 | * @param startPos the position in the text where we should start looking for 472 | * an emoji end 473 | * 474 | * @return the end index of the unicode emoji starting at startPos. -1 if not 475 | * found 476 | */ 477 | protected static int getEmojiEndPos(char[] text, int startPos) { 478 | int best = -1; 479 | for (int j = startPos + 1; j <= text.length; j++) { 480 | EmojiTrie.Matches status = EmojiManager.EMOJI_TRIE.isEmoji(text, startPos, j); 481 | 482 | if (status.exactMatch()) { 483 | best = j; 484 | } else if (status.impossibleMatch()) { 485 | return best; 486 | } 487 | } 488 | 489 | return best; 490 | } 491 | 492 | 493 | public static class UnicodeCandidate { 494 | private final Emoji emoji; 495 | private final Fitzpatrick fitzpatrick; 496 | private final int startIndex; 497 | 498 | private UnicodeCandidate(Emoji emoji, String fitzpatrick, int startIndex) { 499 | this.emoji = emoji; 500 | this.fitzpatrick = Fitzpatrick.fitzpatrickFromUnicode(fitzpatrick); 501 | this.startIndex = startIndex; 502 | } 503 | 504 | public Emoji getEmoji() { 505 | return emoji; 506 | } 507 | 508 | public boolean hasFitzpatrick() { 509 | return getFitzpatrick() != null; 510 | } 511 | 512 | public Fitzpatrick getFitzpatrick() { 513 | return fitzpatrick; 514 | } 515 | 516 | public String getFitzpatrickType() { 517 | return hasFitzpatrick() ? fitzpatrick.name().toLowerCase() : ""; 518 | } 519 | 520 | public String getFitzpatrickUnicode() { 521 | return hasFitzpatrick() ? fitzpatrick.unicode : ""; 522 | } 523 | 524 | public int getEmojiStartIndex() { 525 | return startIndex; 526 | } 527 | 528 | public int getEmojiEndIndex() { 529 | return startIndex + emoji.getUnicode().length(); 530 | } 531 | 532 | public int getFitzpatrickEndIndex() { 533 | return getEmojiEndIndex() + (fitzpatrick != null ? 2 : 0); 534 | } 535 | } 536 | 537 | 538 | protected static class AliasCandidate { 539 | public final Emoji emoji; 540 | public final Fitzpatrick fitzpatrick; 541 | public final int startIndex; 542 | public final int endIndex; 543 | 544 | private AliasCandidate(Emoji emoji, Fitzpatrick fitzpatrick, int startIndex, int endIndex) { 545 | this.emoji = emoji; 546 | this.fitzpatrick = fitzpatrick; 547 | this.startIndex = startIndex; 548 | this.endIndex = endIndex; 549 | } 550 | } 551 | 552 | /** 553 | * Enum used to indicate what should be done when a Fitzpatrick modifier is 554 | * found. 555 | */ 556 | public enum FitzpatrickAction { 557 | /** 558 | * Tries to match the Fitzpatrick modifier with the previous emoji 559 | */ 560 | PARSE, 561 | 562 | /** 563 | * Removes the Fitzpatrick modifier from the string 564 | */ 565 | REMOVE, 566 | 567 | /** 568 | * Ignores the Fitzpatrick modifier (it will stay in the string) 569 | */ 570 | IGNORE 571 | } 572 | 573 | public interface EmojiTransformer { 574 | String transform(UnicodeCandidate unicodeCandidate); 575 | } 576 | } 577 | -------------------------------------------------------------------------------- /src/main/java/com/vdurmont/emoji/EmojiTrie.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class EmojiTrie { 8 | private final Node root = new Node(); 9 | final int maxDepth; 10 | 11 | public EmojiTrie(Collection emojis) { 12 | int maxDepth = 0; 13 | for (Emoji emoji : emojis) { 14 | Node tree = root; 15 | char[] chars = emoji.getUnicode().toCharArray(); 16 | maxDepth = Math.max(maxDepth, chars.length); 17 | for (char c: chars) { 18 | if (!tree.hasChild(c)) { 19 | tree.addChild(c); 20 | } 21 | tree = tree.getChild(c); 22 | } 23 | tree.setEmoji(emoji); 24 | } 25 | this.maxDepth = maxDepth; 26 | } 27 | 28 | 29 | /** 30 | * Checks if sequence of chars contain an emoji. 31 | * 32 | * @param sequence Sequence of char that may contain emoji in full or 33 | * partially. 34 | * 35 | * @return 36 | * <li> 37 | * Matches.EXACTLY if char sequence in its entirety is an emoji 38 | * </li> 39 | * <li> 40 | * Matches.POSSIBLY if char sequence matches prefix of an emoji 41 | * </li> 42 | * <li> 43 | * Matches.IMPOSSIBLE if char sequence matches no emoji or prefix of an 44 | * emoji 45 | * </li> 46 | */ 47 | public Matches isEmoji(char[] sequence) { 48 | return isEmoji(sequence, 0, sequence.length); 49 | } 50 | 51 | /** 52 | * Checks if the sequence of chars within the given bound indices contain an emoji. 53 | * @see #isEmoji(char[]) 54 | */ 55 | public Matches isEmoji(char[] sequence, int start, int end) { 56 | if (start < 0 || start > end || end > sequence.length) { 57 | throw new ArrayIndexOutOfBoundsException( 58 | "start " + start + ", end " + end + ", length " + sequence.length); 59 | } 60 | 61 | if (sequence == null) { 62 | return Matches.POSSIBLY; 63 | } 64 | 65 | Node tree = root; 66 | for (int i = start; i < end; i++) { 67 | if (!tree.hasChild(sequence[i])) { 68 | return Matches.IMPOSSIBLE; 69 | } 70 | tree = tree.getChild(sequence[i]); 71 | } 72 | 73 | return tree.isEndOfEmoji() ? Matches.EXACTLY : Matches.POSSIBLY; 74 | } 75 | 76 | 77 | /** 78 | * Finds Emoji instance from emoji unicode 79 | * @param unicode unicode of emoji to get 80 | * @return Emoji instance if unicode matches and emoji, null otherwise. 81 | */ 82 | public Emoji getEmoji(String unicode) { 83 | return getEmoji(unicode.toCharArray(), 0, unicode.length()); 84 | } 85 | 86 | Emoji getEmoji(char[] sequence, int start, int end) { 87 | if (start < 0 || start > end || end > sequence.length) { 88 | throw new ArrayIndexOutOfBoundsException( 89 | "start " + start + ", end " + end + ", length " + sequence.length); 90 | } 91 | 92 | Node tree = root; 93 | for (int i = 0; i < end; i++) { 94 | if (!tree.hasChild(sequence[i])) { 95 | return null; 96 | } 97 | tree = tree.getChild(sequence[i]); 98 | } 99 | return tree.getEmoji(); 100 | } 101 | 102 | public enum Matches { 103 | EXACTLY, POSSIBLY, IMPOSSIBLE; 104 | 105 | public boolean exactMatch() { 106 | return this == EXACTLY; 107 | } 108 | 109 | public boolean impossibleMatch() { 110 | return this == IMPOSSIBLE; 111 | } 112 | } 113 | 114 | private class Node { 115 | private Map children = new HashMap(); 116 | private Emoji emoji; 117 | 118 | private void setEmoji(Emoji emoji) { 119 | this.emoji = emoji; 120 | } 121 | 122 | private Emoji getEmoji() { 123 | return emoji; 124 | } 125 | 126 | private boolean hasChild(char child) { 127 | return children.containsKey(child); 128 | } 129 | 130 | private void addChild(char child) { 131 | children.put(child, new Node()); 132 | } 133 | 134 | private Node getChild(char child) { 135 | return children.get(child); 136 | } 137 | 138 | private boolean isEndOfEmoji() { 139 | return emoji != null; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/com/vdurmont/emoji/Fitzpatrick.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | /** 4 | * Enum that represents the Fitzpatrick modifiers supported by the emojis. 5 | */ 6 | public enum Fitzpatrick { 7 | /** 8 | * Fitzpatrick modifier of type 1/2 (pale white/white) 9 | */ 10 | TYPE_1_2("\uD83C\uDFFB"), 11 | 12 | /** 13 | * Fitzpatrick modifier of type 3 (cream white) 14 | */ 15 | TYPE_3("\uD83C\uDFFC"), 16 | 17 | /** 18 | * Fitzpatrick modifier of type 4 (moderate brown) 19 | */ 20 | TYPE_4("\uD83C\uDFFD"), 21 | 22 | /** 23 | * Fitzpatrick modifier of type 5 (dark brown) 24 | */ 25 | TYPE_5("\uD83C\uDFFE"), 26 | 27 | /** 28 | * Fitzpatrick modifier of type 6 (black) 29 | */ 30 | TYPE_6("\uD83C\uDFFF"); 31 | 32 | /** 33 | * The unicode representation of the Fitzpatrick modifier 34 | */ 35 | public final String unicode; 36 | 37 | Fitzpatrick(String unicode) { 38 | this.unicode = unicode; 39 | } 40 | 41 | 42 | public static Fitzpatrick fitzpatrickFromUnicode(String unicode) { 43 | for (Fitzpatrick v : values()) { 44 | if (v.unicode.equals(unicode)) { 45 | return v; 46 | } 47 | } 48 | return null; 49 | } 50 | 51 | public static Fitzpatrick fitzpatrickFromType(String type) { 52 | try { 53 | return Fitzpatrick.valueOf(type.toUpperCase()); 54 | } catch (IllegalArgumentException e) { 55 | return null; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/vdurmont/emoji/EmojiJsonTest.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.Parameterized; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.util.*; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | /** 18 | * Test that checks emoji json. 19 | *

20 | * Currently contains checks for: 21 | *

    22 | *
  • Unicode emoji presents in json
  • 23 | *
  • Right fitzpatric flag for emoji
  • 24 | *
25 | * 26 | *

27 | * The test data is taken from: Unicode test data 28 | * related to unicode 9.0 29 | */ 30 | @RunWith(Parameterized.class) 31 | public class EmojiJsonTest { 32 | @Parameterized.Parameters 33 | public static Collection emojis() throws IOException { 34 | final InputStream is = EmojiJsonTest.class.getClassLoader().getResourceAsStream("emoji-test.txt"); 35 | return EmojiTestDataReader.getEmojiList(is); 36 | } 37 | 38 | private static final int[] FITZPATRIC_CODEPOINTS = new int[]{ 39 | EmojiTestDataReader.convertFromCodepoint("1F3FB"), 40 | EmojiTestDataReader.convertFromCodepoint("1F3FC"), 41 | EmojiTestDataReader.convertFromCodepoint("1F3FD"), 42 | EmojiTestDataReader.convertFromCodepoint("1F3FE"), 43 | EmojiTestDataReader.convertFromCodepoint("1F3FF") 44 | }; 45 | 46 | @Parameterized.Parameter 47 | public String emoji; 48 | 49 | @Ignore("1665 emoji still has not been added") 50 | @Test 51 | public void checkEmojiExisting() { 52 | assertTrue("Asserting for emoji: " + emoji, EmojiManager.isEmoji(emoji)); 53 | } 54 | 55 | @Test 56 | public void checkEmojiFitzpatricFlag() { 57 | final int len = emoji.toCharArray().length; 58 | boolean shouldContainFitzpatric = false; 59 | int codepoint; 60 | for (int i = 0; i < len; i++) { 61 | codepoint = emoji.codePointAt(i); 62 | shouldContainFitzpatric = Arrays.binarySearch(FITZPATRIC_CODEPOINTS, codepoint) >= 0; 63 | if (shouldContainFitzpatric) { 64 | break; 65 | } 66 | } 67 | 68 | if (shouldContainFitzpatric) { 69 | EmojiParser.parseFromUnicode(emoji, new EmojiParser.EmojiTransformer() { 70 | public String transform(EmojiParser.UnicodeCandidate unicodeCandidate) { 71 | if (unicodeCandidate.hasFitzpatrick()) { 72 | assertTrue("Asserting emoji contains fitzpatric: " + emoji + " " + unicodeCandidate.getEmoji(), 73 | unicodeCandidate.getEmoji().supportsFitzpatrick()); 74 | } 75 | return ""; 76 | } 77 | }); 78 | } 79 | } 80 | 81 | private static class EmojiTestDataReader { 82 | static List getEmojiList(final InputStream emojiFileStream) throws IOException { 83 | final BufferedReader reader = new BufferedReader(new InputStreamReader(emojiFileStream)); 84 | final List result = new LinkedList(); 85 | 86 | String line = reader.readLine(); 87 | String [] lineSplit; 88 | while (line != null) { 89 | if (!line.startsWith("#") && !line.startsWith(" ") && !line.startsWith("\n") && 90 | line.length() != 0) { 91 | lineSplit = line.split(";"); 92 | result.add(convertToEmoji(lineSplit[0].trim())); 93 | } 94 | line = reader.readLine(); 95 | } 96 | return result; 97 | } 98 | 99 | private static String convertToEmoji(final String input) { 100 | String[] emojiCodepoints = input.split(" "); 101 | StringBuilder sb = new StringBuilder(); 102 | for (String emojiCodepoint : emojiCodepoints) { 103 | int codePoint = convertFromCodepoint(emojiCodepoint); 104 | sb.append(Character.toChars(codePoint)); 105 | } 106 | return sb.toString(); 107 | } 108 | 109 | static int convertFromCodepoint(String emojiCodepointAsString) { 110 | return Integer.parseInt(emojiCodepointAsString, 16); 111 | } 112 | 113 | } 114 | 115 | @Test 116 | public void checkInverseParse() { 117 | assertEquals(emoji, EmojiParser.parseToUnicode(EmojiParser.parseToHtmlDecimal(emoji, EmojiParser.FitzpatrickAction.IGNORE))); 118 | 119 | assertEquals(emoji, EmojiParser.parseToUnicode(EmojiParser.parseToHtmlHexadecimal(emoji, EmojiParser.FitzpatrickAction.IGNORE))); 120 | 121 | assertEquals(emoji, EmojiParser.parseToUnicode(EmojiParser.parseToAliases(emoji, EmojiParser.FitzpatrickAction.IGNORE))); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/com/vdurmont/emoji/EmojiLoaderTest.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.junit.runners.JUnit4; 8 | 9 | import java.io.ByteArrayInputStream; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.UnsupportedEncodingException; 13 | import java.util.List; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertFalse; 17 | import static org.junit.Assert.assertNotNull; 18 | import static org.junit.Assert.assertNull; 19 | import static org.junit.Assert.assertTrue; 20 | 21 | @RunWith(JUnit4.class) 22 | public class EmojiLoaderTest { 23 | @Test 24 | public void load_empty_database_returns_empty_list() throws IOException { 25 | // GIVEN 26 | byte[] bytes = new JSONArray().toString().getBytes("UTF-8"); 27 | InputStream stream = new ByteArrayInputStream(bytes); 28 | 29 | // WHEN 30 | List emojis = EmojiLoader.loadEmojis(stream); 31 | 32 | // THEN 33 | assertEquals(0, emojis.size()); 34 | } 35 | 36 | @Test 37 | public void buildEmojiFromJSON() throws UnsupportedEncodingException { 38 | // GIVEN 39 | JSONObject json = new JSONObject("{" 40 | + "\"emoji\": \"😄\"," 41 | + "\"description\": \"smiling face with open mouth and smiling eyes\"," 42 | + "\"aliases\": [\"smile\"]," 43 | + "\"tags\": [\"happy\", \"joy\", \"pleased\"]" 44 | + "}"); 45 | 46 | // WHEN 47 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 48 | 49 | // THEN 50 | assertNotNull(emoji); 51 | assertEquals("😄", emoji.getUnicode()); 52 | assertEquals( 53 | "smiling face with open mouth and smiling eyes", 54 | emoji.getDescription() 55 | ); 56 | assertEquals(1, emoji.getAliases().size()); 57 | assertEquals("smile", emoji.getAliases().get(0)); 58 | assertEquals(3, emoji.getTags().size()); 59 | assertEquals("happy", emoji.getTags().get(0)); 60 | assertEquals("joy", emoji.getTags().get(1)); 61 | assertEquals("pleased", emoji.getTags().get(2)); 62 | } 63 | 64 | @Test 65 | public void buildEmojiFromJSON_without_description_sets_a_null_description() 66 | throws UnsupportedEncodingException { 67 | // GIVEN 68 | JSONObject json = new JSONObject("{" 69 | + "\"emoji\": \"😄\"," 70 | + "\"aliases\": [\"smile\"]," 71 | + "\"tags\": [\"happy\", \"joy\", \"pleased\"]" 72 | + "}"); 73 | 74 | // WHEN 75 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 76 | 77 | // THEN 78 | assertNotNull(emoji); 79 | assertNull(emoji.getDescription()); 80 | } 81 | 82 | @Test 83 | public void buildEmojiFromJSON_without_unicode_returns_null() 84 | throws UnsupportedEncodingException { 85 | // GIVEN 86 | JSONObject json = new JSONObject("{" 87 | + "\"aliases\": [\"smile\"]," 88 | + "\"tags\": [\"happy\", \"joy\", \"pleased\"]" 89 | + "}"); 90 | 91 | // WHEN 92 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 93 | 94 | // THEN 95 | assertNull(emoji); 96 | } 97 | 98 | @Test 99 | public void buildEmojiFromJSON_computes_the_html_codes() 100 | throws UnsupportedEncodingException { 101 | // GIVEN 102 | JSONObject json = new JSONObject("{" 103 | + "\"emoji\": \"😄\"," 104 | + "\"description\": \"smiling face with open mouth and smiling eyes\"," 105 | + "\"aliases\": [\"smile\"]," 106 | + "\"tags\": [\"happy\", \"joy\", \"pleased\"]" 107 | + "}"); 108 | 109 | // WHEN 110 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 111 | 112 | // THEN 113 | assertNotNull(emoji); 114 | assertEquals("😄", emoji.getUnicode()); 115 | assertEquals("😄", emoji.getHtmlDecimal()); 116 | assertEquals("😄", emoji.getHtmlHexadecimal()); 117 | } 118 | 119 | @Test 120 | public void buildEmojiFromJSON_with_support_for_fitzpatrick_true() 121 | throws UnsupportedEncodingException { 122 | // GIVEN 123 | JSONObject json = new JSONObject("{" 124 | + "\"emoji\": \"\uD83D\uDC66\"," 125 | + "\"description\": \"boy\"," 126 | + "\"supports_fitzpatrick\": true," 127 | + "\"aliases\": [\"boy\"]," 128 | + "\"tags\": [\"child\"]" 129 | + "}"); 130 | 131 | // WHEN 132 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 133 | 134 | // THEN 135 | assertNotNull(emoji); 136 | assertTrue(emoji.supportsFitzpatrick()); 137 | } 138 | 139 | @Test 140 | public void buildEmojiFromJSON_with_support_for_fitzpatrick_false() 141 | throws UnsupportedEncodingException { 142 | // GIVEN 143 | JSONObject json = new JSONObject("{" 144 | + "\"emoji\": \"\uD83D\uDE15\"," 145 | + "\"description\": \"confused face\"," 146 | + "\"supports_fitzpatrick\": false," 147 | + "\"aliases\": [\"confused\"]," 148 | + "\"tags\": []" 149 | + "}"); 150 | 151 | // WHEN 152 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 153 | 154 | // THEN 155 | assertNotNull(emoji); 156 | assertFalse(emoji.supportsFitzpatrick()); 157 | } 158 | 159 | @Test 160 | public void buildEmojiFromJSON_without_support_for_fitzpatrick() 161 | throws UnsupportedEncodingException { 162 | // GIVEN 163 | JSONObject json = new JSONObject("{" 164 | + "\"emoji\": \"\uD83D\uDE15\"," 165 | + "\"description\": \"confused face\"," 166 | + "\"aliases\": [\"confused\"]," 167 | + "\"tags\": []" 168 | + "}"); 169 | 170 | // WHEN 171 | Emoji emoji = EmojiLoader.buildEmojiFromJSON(json); 172 | 173 | // THEN 174 | assertNotNull(emoji); 175 | assertFalse(emoji.supportsFitzpatrick()); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/test/java/com/vdurmont/emoji/EmojiManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.JUnit4; 6 | 7 | import java.util.Collection; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertFalse; 13 | import static org.junit.Assert.assertNull; 14 | import static org.junit.Assert.assertTrue; 15 | 16 | @RunWith(JUnit4.class) 17 | public class EmojiManagerTest { 18 | @Test 19 | public void getForTag_with_unknown_tag_returns_null() { 20 | // GIVEN 21 | 22 | // WHEN 23 | Set emojis = EmojiManager.getForTag("jkahsgdfjksghfjkshf"); 24 | 25 | // THEN 26 | assertNull(emojis); 27 | } 28 | 29 | @Test 30 | public void getForTag_returns_the_emojis_for_the_tag() { 31 | // GIVEN 32 | 33 | // WHEN 34 | Set emojis = EmojiManager.getForTag("happy"); 35 | 36 | // THEN 37 | assertEquals(4, emojis.size()); 38 | assertTrue(TestTools.containsEmojis( 39 | emojis, 40 | "smile", 41 | "smiley", 42 | "grinning", 43 | "satisfied" 44 | )); 45 | } 46 | 47 | @Test 48 | public void getForTag_returns_the_eu_emoji_for_same_tag() { 49 | // GIVEN 50 | 51 | // WHEN 52 | Set emojis = EmojiManager.getForTag("european union"); 53 | 54 | // THEN 55 | assertEquals(1, emojis.size()); 56 | assertTrue(TestTools.containsEmojis(emojis, "eu")); 57 | } 58 | 59 | @Test 60 | public void getForAlias_with_unknown_alias_returns_null() { 61 | // GIVEN 62 | 63 | // WHEN 64 | Emoji emoji = EmojiManager.getForAlias("jkahsgdfjksghfjkshf"); 65 | 66 | // THEN 67 | assertNull(emoji); 68 | } 69 | 70 | @Test 71 | public void getForAlias_returns_the_emoji_for_the_alias() { 72 | // GIVEN 73 | 74 | // WHEN 75 | Emoji emoji = EmojiManager.getForAlias("smile"); 76 | 77 | // THEN 78 | assertEquals( 79 | "smiling face with open mouth and smiling eyes", 80 | emoji.getDescription() 81 | ); 82 | } 83 | 84 | @Test 85 | public void getForAlias_with_colons_returns_the_emoji_for_the_alias() { 86 | // GIVEN 87 | 88 | // WHEN 89 | Emoji emoji = EmojiManager.getForAlias(":smile:"); 90 | 91 | // THEN 92 | assertEquals( 93 | "smiling face with open mouth and smiling eyes", 94 | emoji.getDescription() 95 | ); 96 | } 97 | 98 | @Test 99 | public void isEmoji_for_an_emoji_returns_true() { 100 | // GIVEN 101 | String emoji = "😀"; 102 | 103 | // WHEN 104 | boolean isEmoji = EmojiManager.isEmoji(emoji); 105 | 106 | // THEN 107 | assertTrue(isEmoji); 108 | } 109 | 110 | @Test 111 | public void isEmoji_with_fitzpatric_modifier_returns_true() { 112 | // GIVEN 113 | String emoji = "\uD83E\uDD30\uD83C\uDFFB"; 114 | 115 | // WHEN 116 | boolean isEmoji = EmojiManager.isEmoji(emoji); 117 | 118 | // THEN 119 | assertTrue(isEmoji); 120 | } 121 | 122 | @Test 123 | public void isEmoji_for_a_non_emoji_returns_false() { 124 | // GIVEN 125 | String str = "test"; 126 | 127 | // WHEN 128 | boolean isEmoji = EmojiManager.isEmoji(str); 129 | 130 | // THEN 131 | assertFalse(isEmoji); 132 | } 133 | 134 | @Test 135 | public void isEmoji_for_an_emoji_and_other_chars_returns_false() { 136 | // GIVEN 137 | String str = "😀 test"; 138 | 139 | // WHEN 140 | boolean isEmoji = EmojiManager.isEmoji(str); 141 | 142 | // THEN 143 | assertFalse(isEmoji); 144 | } 145 | 146 | @Test 147 | public void containsEmoji_with_fitzpatric_modifier_returns_true() { 148 | // GIVEN 149 | String emoji = "\uD83E\uDD30\uD83C\uDFFB"; 150 | 151 | // WHEN 152 | boolean containsEmoji = EmojiManager.containsEmoji(emoji); 153 | 154 | // THEN 155 | assertTrue(containsEmoji); 156 | } 157 | 158 | @Test 159 | public void containsEmoji_for_a_non_emoji_returns_false() { 160 | // GIVEN 161 | String str = "test"; 162 | 163 | // WHEN 164 | boolean containsEmoji = EmojiManager.containsEmoji(str); 165 | 166 | // THEN 167 | assertFalse(containsEmoji); 168 | } 169 | 170 | @Test 171 | public void containsEmoji_for_an_emoji_and_other_chars_returns_true() { 172 | // GIVEN 173 | String str = "😀 test"; 174 | 175 | // WHEN 176 | boolean containsEmoji = EmojiManager.containsEmoji(str); 177 | 178 | // THEN 179 | assertTrue(containsEmoji); 180 | } 181 | 182 | @Test 183 | public void isOnlyEmojis_for_an_emoji_returns_true() { 184 | // GIVEN 185 | String str = "😀"; 186 | 187 | // WHEN 188 | boolean isEmoji = EmojiManager.isOnlyEmojis(str); 189 | 190 | // THEN 191 | assertTrue(isEmoji); 192 | } 193 | 194 | @Test 195 | public void isOnlyEmojis_for_emojis_returns_true() { 196 | // GIVEN 197 | String str = "😀😀😀"; 198 | 199 | // WHEN 200 | boolean isEmoji = EmojiManager.isOnlyEmojis(str); 201 | 202 | // THEN 203 | assertTrue(isEmoji); 204 | } 205 | 206 | @Test 207 | public void isOnlyEmojis_for_random_string_returns_false() { 208 | // GIVEN 209 | String str = "😀a"; 210 | 211 | // WHEN 212 | boolean isEmoji = EmojiManager.isOnlyEmojis(str); 213 | 214 | // THEN 215 | assertFalse(isEmoji); 216 | } 217 | 218 | @Test 219 | public void getAllTags_returns_the_tags() { 220 | // GIVEN 221 | 222 | // WHEN 223 | Collection tags = EmojiManager.getAllTags(); 224 | 225 | // THEN 226 | // We know the number of distinct tags int the...! 227 | assertEquals(656, tags.size()); 228 | } 229 | 230 | @Test 231 | public void getAll_doesnt_return_duplicates() { 232 | // GIVEN 233 | 234 | // WHEN 235 | Collection emojis = EmojiManager.getAll(); 236 | 237 | // THEN 238 | Set unicodes = new HashSet(); 239 | for (Emoji emoji : emojis) { 240 | assertFalse( 241 | "Duplicate: " + emoji.getDescription(), 242 | unicodes.contains(emoji.getUnicode()) 243 | ); 244 | unicodes.add(emoji.getUnicode()); 245 | } 246 | assertEquals(unicodes.size(), emojis.size()); 247 | } 248 | 249 | @Test 250 | public void no_duplicate_alias() { 251 | // GIVEN 252 | 253 | // WHEN 254 | Collection emojis = EmojiManager.getAll(); 255 | 256 | // THEN 257 | Set aliases = new HashSet(); 258 | Set duplicates = new HashSet(); 259 | for (Emoji emoji : emojis) { 260 | for (String alias : emoji.getAliases()) { 261 | if (aliases.contains(alias)) { 262 | duplicates.add(alias); 263 | } 264 | aliases.add(alias); 265 | } 266 | } 267 | assertEquals("Duplicates: " + duplicates, duplicates.size(), 0); 268 | } 269 | 270 | @Test 271 | public void getByUnicode_returns_correct_emoji() { 272 | String wavingHand = "\uD83D\uDC4B"; 273 | Emoji e = EmojiManager.getByUnicode(wavingHand); 274 | assertEquals(wavingHand, e.getUnicode()); 275 | assertEquals("waving hand sign", e.getDescription()); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/test/java/com/vdurmont/emoji/EmojiParserTest.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | import com.vdurmont.emoji.EmojiParser.AliasCandidate; 4 | import com.vdurmont.emoji.EmojiParser.FitzpatrickAction; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.junit.runners.JUnit4; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | import static org.junit.Assert.assertNull; 14 | import static org.junit.Assert.assertTrue; 15 | 16 | @RunWith(JUnit4.class) 17 | public class EmojiParserTest { 18 | @Test 19 | public void parseToAliases_replaces_the_emojis_by_one_of_their_aliases() { 20 | // GIVEN 21 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 22 | 23 | // WHEN 24 | String result = EmojiParser.parseToAliases(str); 25 | 26 | // THEN 27 | assertEquals( 28 | "An :grinning:awesome :smiley:string with a few :wink:emojis!", 29 | result 30 | ); 31 | } 32 | 33 | @Test 34 | public void replaceAllEmojis_replace_the_emojis_by_string() throws Exception { 35 | // GIVEN 36 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 37 | 38 | // WHEN 39 | String result = EmojiParser.replaceAllEmojis(str, ":)"); 40 | 41 | // THEN 42 | assertEquals( 43 | "An :)awesome :)string with a few :)emojis!", 44 | result 45 | ); 46 | } 47 | 48 | 49 | @Test 50 | public void parseToAliases_REPLACE_with_a_fitzpatrick_modifier() { 51 | // GIVEN 52 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 53 | 54 | // WHEN 55 | String result = EmojiParser.parseToAliases(str); 56 | 57 | // THEN 58 | assertEquals(":boy|type_6:", result); 59 | } 60 | 61 | @Test 62 | public void parseToAliases_REMOVE_with_a_fitzpatrick_modifier() { 63 | // GIVEN 64 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 65 | 66 | // WHEN 67 | String result = EmojiParser.parseToAliases(str, FitzpatrickAction.REMOVE); 68 | 69 | // THEN 70 | assertEquals(":boy:", result); 71 | } 72 | 73 | @Test 74 | public void parseToAliases_REMOVE_without_a_fitzpatrick_modifier() { 75 | // GIVEN 76 | String str = "\uD83D\uDC66"; 77 | 78 | // WHEN 79 | String result = EmojiParser.parseToAliases(str, FitzpatrickAction.REMOVE); 80 | 81 | // THEN 82 | assertEquals(":boy:", result); 83 | } 84 | 85 | @Test 86 | public void parseToAliases_IGNORE_with_a_fitzpatrick_modifier() { 87 | // GIVEN 88 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 89 | 90 | // WHEN 91 | String result = EmojiParser.parseToAliases(str, FitzpatrickAction.IGNORE); 92 | 93 | // THEN 94 | assertEquals(":boy:\uD83C\uDFFF", result); 95 | } 96 | 97 | @Test 98 | public void parseToAliases_IGNORE_without_a_fitzpatrick_modifier() { 99 | // GIVEN 100 | String str = "\uD83D\uDC66"; 101 | 102 | // WHEN 103 | String result = EmojiParser.parseToAliases(str, FitzpatrickAction.IGNORE); 104 | 105 | // THEN 106 | assertEquals(":boy:", result); 107 | } 108 | 109 | @Test 110 | public void parseToAliases_with_long_overlapping_emoji() { 111 | // GIVEN 112 | String str = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66"; 113 | 114 | // WHEN 115 | String result = EmojiParser.parseToAliases(str); 116 | 117 | //With greedy parsing, this will give :man::woman::boy: 118 | //THEN 119 | assertEquals(":family_man_woman_boy:", result); 120 | } 121 | 122 | @Test 123 | public void parseToAliases_continuous_non_overlapping_emojis() { 124 | // GIVEN 125 | String str = "\uD83D\uDC69\uD83D\uDC68\uD83D\uDC66"; 126 | 127 | // WHEN 128 | String result = EmojiParser.parseToAliases(str); 129 | 130 | //THEN 131 | assertEquals(":woman::man::boy:", result); 132 | } 133 | 134 | @Test 135 | public void parseToHtmlDecimal_replaces_the_emojis_by_their_html_decimal_representation() { 136 | // GIVEN 137 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 138 | 139 | // WHEN 140 | String result = EmojiParser.parseToHtmlDecimal(str); 141 | 142 | // THEN 143 | assertEquals( 144 | "An 😀awesome 😃string with a few 😉emojis!", 145 | result 146 | ); 147 | } 148 | 149 | @Test 150 | public void parseToHtmlDecimal_PARSE_with_a_fitzpatrick_modifier() { 151 | // GIVEN 152 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 153 | 154 | // WHEN 155 | String result = EmojiParser.parseToHtmlDecimal( 156 | str, 157 | FitzpatrickAction.PARSE 158 | ); 159 | 160 | // THEN 161 | assertEquals("👦", result); 162 | } 163 | 164 | @Test 165 | public void parseToHtmlDecimal_REMOVE_with_a_fitzpatrick_modifier() { 166 | // GIVEN 167 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 168 | 169 | // WHEN 170 | String result = EmojiParser.parseToHtmlDecimal( 171 | str, 172 | FitzpatrickAction.REMOVE 173 | ); 174 | 175 | // THEN 176 | assertEquals("👦", result); 177 | } 178 | 179 | @Test 180 | public void parseToHtmlDecimal_IGNORE_with_a_fitzpatrick_modifier() { 181 | // GIVEN 182 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 183 | 184 | // WHEN 185 | String result = EmojiParser.parseToHtmlDecimal( 186 | str, 187 | FitzpatrickAction.IGNORE 188 | ); 189 | 190 | // THEN 191 | assertEquals("👦\uD83C\uDFFF", result); 192 | } 193 | 194 | @Test 195 | public void parseToHtmlHexadecimal_replaces_the_emojis_by_their_htm_hex_representation() { 196 | // GIVEN 197 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 198 | 199 | // WHEN 200 | String result = EmojiParser.parseToHtmlHexadecimal(str); 201 | 202 | // THEN 203 | assertEquals( 204 | "An 😀awesome 😃string with a few 😉emojis!", 205 | result 206 | ); 207 | } 208 | 209 | @Test 210 | public void parseToHtmlHexadecimal_PARSE_with_a_fitzpatrick_modifier() { 211 | // GIVEN 212 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 213 | 214 | // WHEN 215 | String result = EmojiParser.parseToHtmlHexadecimal( 216 | str, 217 | FitzpatrickAction.PARSE 218 | ); 219 | 220 | // THEN 221 | assertEquals("👦", result); 222 | } 223 | 224 | @Test 225 | public void parseToHtmlHexadecimal_REMOVE_with_a_fitzpatrick_modifier() { 226 | // GIVEN 227 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 228 | 229 | // WHEN 230 | String result = EmojiParser.parseToHtmlHexadecimal( 231 | str, 232 | FitzpatrickAction.REMOVE 233 | ); 234 | 235 | // THEN 236 | assertEquals("👦", result); 237 | } 238 | 239 | @Test 240 | public void parseToHtmlHexadecimal_IGNORE_with_a_fitzpatrick_modifier() { 241 | // GIVEN 242 | String str = "\uD83D\uDC66\uD83C\uDFFF"; 243 | 244 | // WHEN 245 | String result = EmojiParser.parseToHtmlHexadecimal( 246 | str, 247 | FitzpatrickAction.IGNORE 248 | ); 249 | 250 | // THEN 251 | assertEquals("👦\uD83C\uDFFF", result); 252 | } 253 | 254 | @Test 255 | public void parseToUnicode_replaces_the_aliases_and_the_html_by_their_emoji() { 256 | // GIVEN 257 | String str = "An :grinning:awesome :smiley:string " + 258 | "😄with a few 😉emojis!"; 259 | 260 | // WHEN 261 | String result = EmojiParser.parseToUnicode(str); 262 | 263 | // THEN 264 | assertEquals("An 😀awesome 😃string 😄with a few 😉emojis!", result); 265 | } 266 | 267 | @Test 268 | public void parseToUnicode_with_the_thumbsup_emoji_replaces_the_alias_by_the_emoji() { 269 | // GIVEN 270 | String str = "An :+1:awesome :smiley:string " + 271 | "😄with a few :wink:emojis!"; 272 | 273 | // WHEN 274 | String result = EmojiParser.parseToUnicode(str); 275 | 276 | // THEN 277 | assertEquals( 278 | "An \uD83D\uDC4Dawesome 😃string 😄with a few 😉emojis!", 279 | result 280 | ); 281 | } 282 | 283 | @Test 284 | public void parseToUnicode_with_the_thumbsdown_emoji_replaces_the_alias_by_the_emoji() { 285 | // GIVEN 286 | String str = "An :-1:awesome :smiley:string 😄" + 287 | "with a few :wink:emojis!"; 288 | 289 | // WHEN 290 | String result = EmojiParser.parseToUnicode(str); 291 | 292 | // THEN 293 | assertEquals( 294 | "An \uD83D\uDC4Eawesome 😃string 😄with a few 😉emojis!", 295 | result 296 | ); 297 | } 298 | 299 | @Test 300 | public void parseToUnicode_with_the_thumbsup_emoji_in_hex_replaces_the_alias_by_the_emoji() { 301 | // GIVEN 302 | String str = "An :+1:awesome :smiley:string 😄" + 303 | "with a few :wink:emojis!"; 304 | 305 | // WHEN 306 | String result = EmojiParser.parseToUnicode(str); 307 | 308 | // THEN 309 | assertEquals( 310 | "An \uD83D\uDC4Dawesome 😃string 😄with a few 😉emojis!", 311 | result 312 | ); 313 | } 314 | 315 | @Test 316 | public void parseToUnicode_with_a_fitzpatrick_modifier() { 317 | // GIVEN 318 | String str = ":boy|type_6:"; 319 | 320 | // WHEN 321 | String result = EmojiParser.parseToUnicode(str); 322 | 323 | // THEN 324 | assertEquals("\uD83D\uDC66\uD83C\uDFFF", result); 325 | } 326 | 327 | @Test 328 | public void parseToUnicode_with_an_unsupported_fitzpatrick_modifier_doesnt_replace() { 329 | // GIVEN 330 | String str = ":grinning|type_6:"; 331 | // WHEN 332 | String result = EmojiParser.parseToUnicode(str); 333 | 334 | // THEN 335 | assertEquals(str, result); 336 | } 337 | 338 | @Test 339 | public void getAliasAt_with_one_alias() { 340 | // GIVEN 341 | String str = "test :boy: test"; 342 | 343 | // WHEN 344 | AliasCandidate candidate = EmojiParser.getAliasAt(str, 5); 345 | 346 | // THEN 347 | assertTrue(candidate.emoji.getAliases().contains("boy")); 348 | assertNull(candidate.fitzpatrick); 349 | } 350 | 351 | @Test 352 | public void getAliasAt_with_one_alias_an_another_colon_after() { 353 | // GIVEN 354 | String str = "test :boy: test:"; 355 | 356 | // WHEN 357 | AliasCandidate candidate = EmojiParser.getAliasAt(str, 5); 358 | 359 | // THEN 360 | assertTrue(candidate.emoji.getAliases().contains("boy")); 361 | assertNull(candidate.fitzpatrick); 362 | } 363 | 364 | @Test 365 | public void getAliasAt_with_one_alias_an_another_colon_right_after() { 366 | // GIVEN 367 | String str = "test :boy::test"; 368 | 369 | // WHEN 370 | AliasCandidate candidate = EmojiParser.getAliasAt(str, 5); 371 | 372 | // THEN 373 | assertTrue(candidate.emoji.getAliases().contains("boy")); 374 | assertNull(candidate.fitzpatrick); 375 | } 376 | 377 | @Test 378 | public void getAliasAt_with_one_alias_an_another_colon_before_after() { 379 | // GIVEN 380 | String str = "test ::boy: test"; 381 | 382 | // WHEN 383 | AliasCandidate candidate = EmojiParser.getAliasAt(str, 5); 384 | assertNull(candidate); 385 | 386 | candidate = EmojiParser.getAliasAt(str, 6); 387 | 388 | // THEN 389 | assertTrue(candidate.emoji.getAliases().contains("boy")); 390 | assertNull(candidate.fitzpatrick); 391 | } 392 | 393 | @Test 394 | public void getAliasAt_with_a_fitzpatrick_modifier() { 395 | // GIVEN 396 | String str = "test :boy|type_3: test"; 397 | 398 | // WHEN 399 | AliasCandidate candidate = EmojiParser.getAliasAt(str, 5); 400 | 401 | // THEN 402 | assertTrue(candidate.emoji.getAliases().contains("boy")); 403 | assertEquals(Fitzpatrick.TYPE_3, candidate.fitzpatrick); 404 | } 405 | 406 | @Test 407 | public void test_with_a_new_flag() { 408 | String input = "Cuba has a new flag! :cu:"; 409 | String expected = "Cuba has a new flag! \uD83C\uDDE8\uD83C\uDDFA"; 410 | 411 | assertEquals(expected, EmojiParser.parseToUnicode(input)); 412 | assertEquals(input, EmojiParser.parseToAliases(expected)); 413 | } 414 | 415 | @Test 416 | public void removeAllEmojis_removes_all_the_emojis_from_the_string() { 417 | // GIVEN 418 | String input = "An 😀awesome 😃string 😄with " + 419 | "a \uD83D\uDC66\uD83C\uDFFFfew 😉emojis!"; 420 | 421 | // WHEN 422 | String result = EmojiParser.removeAllEmojis(input); 423 | 424 | // THEN 425 | String expected = "An awesome string with a few emojis!"; 426 | assertEquals(expected, result); 427 | } 428 | 429 | @Test 430 | public void removeEmojis_only_removes_the_emojis_in_the_iterable_from_the_string() { 431 | // GIVEN 432 | String input = "An\uD83D\uDE03 awesome\uD83D\uDE04 string" + 433 | "\uD83D\uDC4D\uD83C\uDFFF with\uD83D\uDCAA\uD83C\uDFFD a few emojis!"; 434 | 435 | List emojis = new ArrayList(); 436 | emojis.add(EmojiManager.getForAlias("smile")); 437 | emojis.add(EmojiManager.getForAlias("+1")); 438 | 439 | // WHEN 440 | String result = EmojiParser.removeEmojis(input, emojis); 441 | 442 | // THEN 443 | String expected = "An\uD83D\uDE03 awesome string with" + 444 | "\uD83D\uDCAA\uD83C\uDFFD a few emojis!"; 445 | assertEquals(expected, result); 446 | } 447 | 448 | @Test 449 | public void removeAllEmojisExcept_removes_all_the_emojis_from_the_string_except_those_in_the_iterable() { 450 | // GIVEN 451 | String input = "An\uD83D\uDE03 awesome\uD83D\uDE04 string" + 452 | "\uD83D\uDC4D\uD83C\uDFFF with\uD83D\uDCAA\uD83C\uDFFD a few emojis!"; 453 | 454 | List emojis = new ArrayList(); 455 | emojis.add(EmojiManager.getForAlias("smile")); 456 | emojis.add(EmojiManager.getForAlias("+1")); 457 | 458 | // WHEN 459 | String result = EmojiParser.removeAllEmojisExcept(input, emojis); 460 | 461 | // THEN 462 | String expected = "An awesome\uD83D\uDE04 string\uD83D\uDC4D\uD83C\uDFFF " + 463 | "with a few emojis!"; 464 | assertEquals(expected, result); 465 | } 466 | 467 | @Test 468 | public void parseToUnicode_with_the_keycap_asterisk_emoji_replaces_the_alias_by_the_emoji() { 469 | // GIVEN 470 | String str = "Let's test the :keycap_asterisk: emoji and " + 471 | "its other alias :star_keycap:"; 472 | 473 | // WHEN 474 | String result = EmojiParser.parseToUnicode(str); 475 | 476 | // THEN 477 | assertEquals("Let's test the *⃣ emoji and its other alias *⃣", result); 478 | } 479 | 480 | @Test 481 | public void parseToAliases_NG_and_nigeria() { 482 | // GIVEN 483 | String str = "Nigeria is 🇳🇬, NG is 🆖"; 484 | 485 | // WHEN 486 | String result = EmojiParser.parseToAliases(str); 487 | 488 | // THEN 489 | assertEquals("Nigeria is :ng:, NG is :squared_ng:", result); 490 | } 491 | 492 | @Test 493 | public void parseToAliases_couplekiss_woman_woman() { 494 | // GIVEN 495 | String str = "👩‍❤️‍💋‍👩"; 496 | 497 | // WHEN 498 | String result = EmojiParser.parseToAliases(str); 499 | 500 | // THEN 501 | assertEquals(":couplekiss_woman_woman:", result); 502 | } 503 | 504 | @Test 505 | public void extractEmojis() { 506 | // GIVEN 507 | String str = "An 😀awesome 😃string with a few 😉emojis!"; 508 | 509 | // WHEN 510 | List result = EmojiParser.extractEmojis(str); 511 | 512 | // THEN 513 | assertEquals("😀", result.get(0)); 514 | assertEquals("😃", result.get(1)); 515 | assertEquals("😉", result.get(2)); 516 | 517 | } 518 | 519 | @Test 520 | public void extractEmojis_withFitzpatrickModifiers() { 521 | // GIVEN 522 | final String surfer = EmojiManager.getForAlias("surfer").getUnicode(); 523 | final String surfer3 = EmojiManager.getForAlias("surfer").getUnicode(Fitzpatrick.TYPE_3); 524 | final String surfer4 = EmojiManager.getForAlias("surfer").getUnicode(Fitzpatrick.TYPE_4); 525 | final String surfer5 = EmojiManager.getForAlias("surfer").getUnicode(Fitzpatrick.TYPE_5); 526 | final String surfer6 = EmojiManager.getForAlias("surfer").getUnicode(Fitzpatrick.TYPE_6); 527 | final String surfers = surfer + " " + surfer3 + " " + surfer4 + " " + surfer5 + " " + surfer6; 528 | 529 | // WHEN 530 | List result = EmojiParser.extractEmojis(surfers); 531 | 532 | // THEN 533 | assertEquals(5, result.size()); 534 | assertEquals(surfer, result.get(0)); 535 | assertEquals(surfer3, result.get(1)); 536 | assertEquals(surfer4, result.get(2)); 537 | assertEquals(surfer5, result.get(3)); 538 | assertEquals(surfer6, result.get(4)); 539 | 540 | } 541 | 542 | @Test 543 | public void parseToAliases_with_first_medal() { 544 | // GIVEN 545 | String str = "🥇"; 546 | 547 | // WHEN 548 | String result = EmojiParser.parseToAliases(str); 549 | 550 | // THEN 551 | assertEquals(":first_place_medal:", result); 552 | } 553 | } 554 | -------------------------------------------------------------------------------- /src/test/java/com/vdurmont/emoji/TestTools.java: -------------------------------------------------------------------------------- 1 | package com.vdurmont.emoji; 2 | 3 | public class TestTools { 4 | public static boolean containsEmojis( 5 | Iterable emojis, 6 | String... aliases 7 | ) { 8 | for (String alias : aliases) { 9 | boolean contains = containsEmoji(emojis, alias); 10 | if (!contains) { 11 | return false; 12 | } 13 | } 14 | return true; 15 | } 16 | 17 | public static boolean containsEmoji(Iterable emojis, String alias) { 18 | for (Emoji emoji : emojis) { 19 | for (String al : emoji.getAliases()) { 20 | if (alias.equals(al)) { 21 | return true; 22 | } 23 | } 24 | } 25 | return false; 26 | } 27 | } 28 | --------------------------------------------------------------------------------