blob: e5a77ba31606019f4cdc691884aa2eaf9596d158 [file] [log] [blame]
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--><head>
<meta charset='utf-8'/><meta http-equiv='X-UA-Compatible' content='IE=edge'/><meta name='viewport' content='width=device-width, initial-scale=1'/><meta name='keywords' content='groovy, emoji'/><meta name='description' content='Season&apos;s greetings with some emoji fun.'/><title>The Apache Groovy programming language - Blogs - Season&#8217;s Greetings with Emojis</title><link href='../img/favicon.ico' type='image/x-ico' rel='icon'/><link rel='stylesheet' type='text/css' href='../css/bootstrap.css'/><link rel='stylesheet' type='text/css' href='../css/font-awesome.min.css'/><link rel='stylesheet' type='text/css' href='../css/style.css'/><link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css'/>
</head><body>
<div id='fork-me'>
<a href='https://github.com/apache/groovy'>
<img style='position: fixed; top: 20px; right: -58px; border: 0; z-index: 100; transform: rotate(45deg);' src='/img/horizontal-github-ribbon.png'/>
</a>
</div><div id='st-container' class='st-container st-effect-9'>
<nav class='st-menu st-effect-9' id='menu-12'>
<h2 class='icon icon-lab'>Socialize</h2><ul>
<li>
<a href='https://groovy-lang.org/mailing-lists.html' class='icon'><span class='fa fa-envelope'></span> Discuss on the mailing-list</a>
</li><li>
<a href='https://twitter.com/ApacheGroovy' class='icon'><span class='fa fa-twitter'></span> Groovy on Twitter</a>
</li><li>
<a href='https://groovy-lang.org/events.html' class='icon'><span class='fa fa-calendar'></span> Events and conferences</a>
</li><li>
<a href='https://github.com/apache/groovy' class='icon'><span class='fa fa-github'></span> Source code on GitHub</a>
</li><li>
<a href='https://groovy-lang.org/reporting-issues.html' class='icon'><span class='fa fa-bug'></span> Report issues in Jira</a>
</li><li>
<a href='http://stackoverflow.com/questions/tagged/groovy' class='icon'><span class='fa fa-stack-overflow'></span> Stack Overflow questions</a>
</li><li>
<a href='http://groovycommunity.com/' class='icon'><span class='fa fa-slack'></span> Slack Community</a>
</li>
</ul>
</nav><div class='st-pusher'>
<div class='st-content'>
<div class='st-content-inner'>
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]--><div><div class='navbar navbar-default navbar-static-top' role='navigation'>
<div class='container'>
<div class='navbar-header'>
<button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
<span class='sr-only'></span><span class='icon-bar'></span><span class='icon-bar'></span><span class='icon-bar'></span>
</button><a class='navbar-brand' href='../index.html'>
<i class='fa fa-star'></i> Apache Groovy
</a>
</div><div class='navbar-collapse collapse'>
<ul class='nav navbar-nav navbar-right'>
<li class=''><a href='https://groovy-lang.org/learn.html'>Learn</a></li><li class=''><a href='https://groovy-lang.org/documentation.html'>Documentation</a></li><li class=''><a href='/download.html'>Download</a></li><li class=''><a href='https://groovy-lang.org/support.html'>Support</a></li><li class=''><a href='/'>Contribute</a></li><li class=''><a href='https://groovy-lang.org/ecosystem.html'>Ecosystem</a></li><li class=''><a href='/blog'>Blog posts</a></li><li class=''><a href='https://groovy.apache.org/events.html'></a></li><li>
<a data-effect='st-effect-9' class='st-trigger' href='#'>Socialize</a>
</li><li class=''>
<a href='../search.html'>
<i class='fa fa-search'></i>
</a>
</li>
</ul>
</div>
</div>
</div><div id='content' class='page-1'><div class='row'><div class='row-fluid'><div class='col-lg-3'><ul class='nav-sidebar'><li><a href='./'>Blog index</a></li><li class='active'><a href='#doc'>Season&#8217;s Greetings with Emojis</a></li><li><a href='#_jdk_21_new_features' class='anchor-link'>JDK 21 New Features</a></li><li><a href='#_playing_with_emojis_with_groovy' class='anchor-link'>Playing with Emojis with Groovy</a></li><li><a href='#_more_information' class='anchor-link'>More Information</a></li></ul><br/><ul class='nav-sidebar'><li style='padding: 0.35em 0.625em; background-color: #eee'><span>Related posts</span></li><li><a href='./helloworldemoji'>Hello World with Emojis</a></li><li><a href='./deep-learning-and-eclipse-collections'>Deep Learning and Eclipse Collections</a></li><li><a href='./adventures-with-groovyfx'>Adventures with GroovyFX</a></li><li><a href='./fruity-eclipse-collections'>Fruity Eclipse Collections</a></li><li><a href='./zipping-collections-with-groovy'>Zipping Collections with Groovy</a></li><li><a href='./set-operations-with-groovy'>Set Operators with Groovy</a></li></ul></div><div class='col-lg-8 col-lg-pull-0'><a name='doc'></a><h1>Season&#8217;s Greetings with Emojis</h1><p><span>Author: <i>Paul King</i></span><br/><span>Published: 2023-12-23 12:24PM (Last updated: 2024-01-19 10:15PM)</span></p><hr/><div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In a <a href="https://groovy.apache.org/blog/helloworldemoji">previous blog post</a>
we looked at a fun way to write a <em>hello world</em> script using Groovy and Emojis.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s look at some of the additional emoji API calls
available in JDK 21. We&#8217;re using Groovy 5.0.0-alpha-5,
but most of the examples work as is with recent Groovy 4 versions.
Groovy 5, adds one shortcut for making it easier to get to code points
as an array.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_jdk_21_new_features">JDK 21 New Features</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As part of <a href="https://bugs.openjdk.org/browse/JDK-8303018">JDK-8303018</a>, JDK 21 adds the following API calls to <code>java.lang.Character</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">public static boolean isEmoji(int codePoint)
public static boolean isEmojiPresentation(int codePoint)
public static boolean isEmojiModifier(int codePoint)
public static boolean isEmojiModifierBase(int codePoint)
public static boolean isEmojiComponent(int codePoint)
public static boolean isExtendedPictographic(int codePoint)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Also added was equivalent functionality when performing regex matches
using the following special binary properties:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>\p{IsEmoji}</code></p>
</li>
<li>
<p><code>\p{IsEmoji_Presentation}</code></p>
</li>
<li>
<p><code>\p{IsEmoji_Modifier}</code></p>
</li>
<li>
<p><code>\p{IsEmoji_Modifier_Base}</code></p>
</li>
<li>
<p><code>\p{IsEmoji_Component}</code></p>
</li>
<li>
<p><code>\p{IsExtended_Pictographic}</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Let&#8217;s have a look at using these features from Groovy.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_playing_with_emojis_with_groovy">Playing with Emojis with Groovy</h2>
<div class="sectionbody">
<div class="paragraph">
<p>First, we&#8217;ll have a look at a String containing 3 emojis:
a Christmas tree, Mrs Claus, and Santa Claus.
We&#8217;ll check that the 3 Unicode code points for that String
all correspond to emojis using one of the new API calls:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji1.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>We can check using the newly added regex binary properties as well.
The Groovy regex operator (<code>==~</code>) ensures that the String exactly matches 3 emojis:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji2.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>Unicode supports various forms of modification by sequencing Unicode characters.
One of the simplest examples is when some "base" emoji character is followed
by a skin-tone emoji modifier. The two consecutive characters are re-interpreted,
resulting in a single emoji with skin tone.</p>
</div>
<div class="paragraph">
<p>We&#8217;ll see that the Christmas tree cannot be used as an emoji modifier
base, but the two Claus emojis can. Also, we can see that all 5 skin
tone emoji characters can be used as emoji modifiers:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji3.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>Let&#8217;s try some combinations. We&#8217;ll combine the Santa emoji with
some of the skin tones. Depending on your IDE/editor, you&#8217;ll probably
see a single emoji, but it is made up of multiple Unicode code points.</p>
</div>
<div class="paragraph">
<p>If we look at the code points from the "single" emoji,
it will be the same as the "bare" Santa emoji plus the code points
from the skin tone emoji:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji4.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>We are also checking the emoji roles using a regex.
We can see the base followed by the modifier.</p>
</div>
<div class="paragraph">
<p>We can put all this together to check all five toned Santas as follows:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji5.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>Another sequencing trick offered by Unicode is to combine related
emojis to form new ones with an intervening <em>zero width joiner</em> (ZWJ).
For example, you might combine the woman emoji, "👩", possibly with
an additional skin tone emoji, then a ZWJ character (Unicode 200D in hex),
followed by the rocket emoji "🚀", which combined gives
a female astronaut emoji "👩🏽‍🚀".</p>
</div>
<div class="paragraph">
<p>Unicode has a special Mx Claus emoji which can be used to represent
a gender-neutral alternative to Mrs Claus or Santa Claus, or to indicate
a person with strong Christmas spirit. It combines the adult emoji, "🧑",
the ZWJ character, and the Christmas tree emoji.</p>
</div>
<div class="paragraph">
<p>Again if we look at the code points, the code points for the "combined" emoji
is just the code points of the individual components one after the other,
as we see on the first line. The second line shows how to enter the combined
emoji using Unicode. The first and last parts are represented as surrogate
pairs which are combined into the correct code points automatically.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji6.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>The last two lines show checking the combined emoji with regex.
We can check the exact Unicode characters using regex&#8217;s <code>\x{&#8230;&#8203;}</code> notation,
noting that we don&#8217;t use surrogate pairs. We can also check the
emoji names using the <code>\N{&#8230;&#8203;}</code> notation.</p>
</div>
<div class="paragraph">
<p>Combinations aren&#8217;t limited to size two. One of the possible "family" emoji combinations
combines 3 emojis, with interleaved ZWJ characters.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji7.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>We can do similar regex checks as previously, checking the
exact Unicode values or the names.</p>
</div>
<div class="paragraph">
<p>As a final example, let&#8217;s look at the "🙋🏻‍♀️" emoji.
Looking at the first line of code below might lead us to think we have combined
three characters, but checking the size shows there are 5 parts to the
combined emoji. The first and last emojis are already combinations.
The "🙋🏻" emoji combines a base emoji with a skin tone.
The "♀️" emoji combines the female sign character "♀" with a special
<em>variation selector</em> character, which indicates that the previous character
should be treated as an emoji rather than a character.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji8.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>We can put the new emoji API calls through their paces by checking
various properties for each part of the combined emoji.</p>
</div>
<div class="paragraph">
<p>We can do similar checks using regex.
We can check for an exact match of the Unicode characters exactly,
by their emoji names, or by role each part plays as shown below:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="img/emoji9.png" alt="using isEmoji"></span></p>
</div>
<div class="paragraph">
<p>We hope you have enjoyed this little exploration of the
new JDK 21 emoji features.</p>
</div>
<div class="paragraph">
<p>Oh yes, and Season&#8217;s greetings everyone 🎄🎅☃️🎁🌟🎉!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_more_information">More Information</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/paulk-asert/groovy-seasonsgreetings">Source code</a></p>
</li>
<li>
<p><a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Character.html">JDK 21 JavaDoc for java.lang.Character</a></p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=O1oq1sbUnmU">Java 21 Improved Emoji Support 💪 Video</a></p>
</li>
<li>
<p><a href="https://inside.java/2023/11/20/sip089/">Improved Emoji Support in Java 21 - Sip of Java</a></p>
</li>
</ul>
</div>
<div class="sidebarblock">
<div class="content">
<div class="title">Update history</div>
<div class="paragraph">
<p><strong>19/Jan/2024</strong>: Bumped Groovy from 5.0.0-alpha-4 to 5.0.0-alpha-5.</p>
</div>
</div>
</div>
</div>
</div></div></div></div></div><footer id='footer'>
<div class='row'>
<div class='colset-3-footer'>
<div class='col-1'>
<h1>Groovy</h1><ul>
<li><a href='https://groovy-lang.org/learn.html'>Learn</a></li><li><a href='https://groovy-lang.org/documentation.html'>Documentation</a></li><li><a href='/download.html'>Download</a></li><li><a href='https://groovy-lang.org/support.html'>Support</a></li><li><a href='/'>Contribute</a></li><li><a href='https://groovy-lang.org/ecosystem.html'>Ecosystem</a></li><li><a href='/blog'>Blog posts</a></li><li><a href='https://groovy.apache.org/events.html'></a></li>
</ul>
</div><div class='col-2'>
<h1>About</h1><ul>
<li><a href='https://github.com/apache/groovy'>Source code</a></li><li><a href='https://groovy-lang.org/security.html'>Security</a></li><li><a href='https://groovy-lang.org/learn.html#books'>Books</a></li><li><a href='https://groovy-lang.org/thanks.html'>Thanks</a></li><li><a href='http://www.apache.org/foundation/sponsorship.html'>Sponsorship</a></li><li><a href='https://groovy-lang.org/faq.html'>FAQ</a></li><li><a href='https://groovy-lang.org/search.html'>Search</a></li>
</ul>
</div><div class='col-3'>
<h1>Socialize</h1><ul>
<li><a href='https://groovy-lang.org/mailing-lists.html'>Discuss on the mailing-list</a></li><li><a href='https://twitter.com/ApacheGroovy'>Groovy on Twitter</a></li><li><a href='https://groovy-lang.org/events.html'>Events and conferences</a></li><li><a href='https://github.com/apache/groovy'>Source code on GitHub</a></li><li><a href='https://groovy-lang.org/reporting-issues.html'>Report issues in Jira</a></li><li><a href='http://stackoverflow.com/questions/tagged/groovy'>Stack Overflow questions</a></li><li><a href='http://groovycommunity.com/'>Slack Community</a></li>
</ul>
</div><div class='col-right'>
<p>
The Groovy programming language is supported by the <a href='http://www.apache.org'>Apache Software Foundation</a> and the Groovy community.
</p><div text-align='right'>
<img src='../img/asf_logo.png' title='The Apache Software Foundation' alt='The Apache Software Foundation' style='width:60%'/>
</div><p>Apache&reg; and the Apache feather logo are either registered trademarks or trademarks of The Apache Software Foundation.</p>
</div>
</div><div class='clearfix'>&copy; 2003-2024 the Apache Groovy project &mdash; Groovy is Open Source: <a href='http://www.apache.org/licenses/LICENSE-2.0.html' alt='Apache 2 License'>license</a>, <a href='https://privacy.apache.org/policies/privacy-policy-public.html'>privacy policy</a>.</div>
</div>
</footer></div>
</div>
</div>
</div>
</div><script src='../js/vendor/jquery-1.10.2.min.js' defer></script><script src='../js/vendor/classie.js' defer></script><script src='../js/vendor/bootstrap.js' defer></script><script src='../js/vendor/sidebarEffects.js' defer></script><script src='../js/vendor/modernizr-2.6.2.min.js' defer></script><script src='../js/plugins.js' defer></script><script src='https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js'></script><script>document.addEventListener('DOMContentLoaded',prettyPrint)</script>
</body></html>