From cd5584d38d58ca757a6b223a472a1d60deb6f7d1 Mon Sep 17 00:00:00 2001 From: Dominic Fellbaum Date: Fri, 22 Sep 2023 23:03:31 +0200 Subject: [PATCH] - Added more overloaded methods with an varargs Emoji parameter. - All operations now also take non "fully-qualified" emojis into account. --- gradle.properties | 2 +- .../net/fellbaum/jemoji/EmojiManager.java | 130 ++++++++++++------ .../net/fellbaum/jemoji/EmojiManagerTest.java | 51 +++---- 3 files changed, 113 insertions(+), 70 deletions(-) diff --git a/gradle.properties b/gradle.properties index 76d7872..957a10d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,4 +7,4 @@ org.gradle.caching=true group=net.fellbaum description=A Java library for conveniently working with emojis -version=1.2.0 +version=1.3.0 diff --git a/lib/src/main/java/net/fellbaum/jemoji/EmojiManager.java b/lib/src/main/java/net/fellbaum/jemoji/EmojiManager.java index be48880..b62c98f 100644 --- a/lib/src/main/java/net/fellbaum/jemoji/EmojiManager.java +++ b/lib/src/main/java/net/fellbaum/jemoji/EmojiManager.java @@ -36,9 +36,7 @@ public final class EmojiManager { final String fileContent = readFileAsString(); try { final List emojis = new ObjectMapper().readValue(fileContent, new TypeReference>() { - }).stream() - .filter(emoji -> emoji.getQualification() == Qualification.FULLY_QUALIFIED || emoji.getQualification() == Qualification.COMPONENT) - .collect(Collectors.toList()); + }); EMOJI_UNICODE_TO_EMOJI = Collections.unmodifiableMap( emojis.stream().collect(Collectors.toMap(Emoji::getEmoji, Function.identity())) @@ -326,7 +324,18 @@ public static Set extractEmojis(final String text) { * @return The text without emojis. */ public static String removeAllEmojis(final String text) { - return removeEmojis(text, EMOJIS_LENGTH_DESCENDING); + return removeAllEmojisExcept(text, Collections.emptyList()); + } + + /** + * Removes the given emojis from the given text. + * + * @param text The text to remove emojis from. + * @param emojisToRemove The emojis to remove. + * @return The text without the given emojis. + */ + public static String removeEmojis(final String text, final Emoji... emojisToRemove) { + return removeEmojis(text, Arrays.asList(emojisToRemove)); } /** @@ -337,8 +346,31 @@ public static String removeAllEmojis(final String text) { * @return The text without the given emojis. */ public static String removeEmojis(final String text, final Collection emojisToRemove) { - final LinkedHashMap> FIRST_CODEPOINT_TO_EMOJIS_ORDER_CODEPOINT_LENGTH_DESCENDING = emojisToRemove.stream().sorted(EMOJI_CODEPOINT_COMPARATOR).collect(getEmojiLinkedHashMapCollector()); + final Set emojis = new HashSet<>(EMOJIS_LENGTH_DESCENDING); + emojis.removeAll(emojisToRemove); + return removeAllEmojisExcept(text, emojis); + } + + /** + * Removes all emojis except the given emojis from the given text. + * + * @param text The text to remove emojis from. + * @param emojisToKeep The emojis to keep. + * @return The text with only the given emojis. + */ + public static String removeAllEmojisExcept(final String text, final Emoji... emojisToKeep) { + return removeAllEmojisExcept(text, Arrays.asList(emojisToKeep)); + } + /** + * Removes all emojis except the given emojis from the given text. + * + * @param text The text to remove emojis from. + * @param emojisToKeep The emojis to keep. + * @return The text with only the given emojis. + */ + public static String removeAllEmojisExcept(final String text, final Collection emojisToKeep) { + if (isStringNullOrEmpty(text)) return ""; final int[] textCodePointsArray = text.codePoints().toArray(); final long textCodePointsLength = textCodePointsArray.length; @@ -349,7 +381,7 @@ public static String removeEmojis(final String text, final Collection emo final int currentCodepoint = textCodePointsArray[textIndex]; sb.appendCodePoint(currentCodepoint); - final List emojisByCodePoint = FIRST_CODEPOINT_TO_EMOJIS_ORDER_CODEPOINT_LENGTH_DESCENDING.get(currentCodepoint); + final List emojisByCodePoint = EMOJI_FIRST_CODEPOINT_TO_EMOJIS_ORDER_CODEPOINT_LENGTH_DESCENDING.get(currentCodepoint); if (emojisByCodePoint == null) continue; for (final Emoji emoji : emojisByCodePoint) { final int[] emojiCodePointsArray = emoji.getEmoji().codePoints().toArray(); @@ -359,14 +391,20 @@ public static String removeEmojis(final String text, final Collection emo continue; } - for (int i = 0; i < emojiCodePointsLength; i++) { - if (textCodePointsArray[textIndex + i] != emojiCodePointsArray[i]) { + for (int emojiCodePointIndex = 0; emojiCodePointIndex < emojiCodePointsLength; emojiCodePointIndex++) { + //break out because the emoji is not the same + if (textCodePointsArray[textIndex + emojiCodePointIndex] != emojiCodePointsArray[emojiCodePointIndex]) { break; } - if (i == emojiCodePointsLength - 1) { - sb.delete(sb.length() - Character.charCount(currentCodepoint), sb.length()); + if (emojiCodePointIndex == (emojiCodePointsLength - 1)) { textIndex += emojiCodePointsLength - 1; + sb.delete(sb.length() - Character.charCount(currentCodepoint), sb.length()); + + if (emojisToKeep.contains(emoji)) { + // if the emoji should be kept, add it again + sb.append(emoji.getEmoji()); + } continue nextTextIteration; } } @@ -376,31 +414,6 @@ public static String removeEmojis(final String text, final Collection emo return sb.toString(); } - /** - * Removes all emojis except the given emojis from the given text. - * - * @param text The text to remove emojis from. - * @param emojisToKeep The emojis to keep. - * @return The text with only the given emojis. - */ - public static String removeAllEmojisExcept(final String text, final Collection emojisToKeep) { - final Set emojisToRemove = new HashSet<>(EMOJIS_LENGTH_DESCENDING); - emojisToRemove.removeAll(emojisToKeep); - - return removeEmojis(text, emojisToRemove); - } - - /** - * Removes all emojis except the given emojis from the given text. - * - * @param text The text to remove emojis from. - * @param emojisToKeep The emojis to keep. - * @return The text with only the given emojis. - */ - public static String removeAllEmojisExcept(final String text, final Emoji... emojisToKeep) { - return removeAllEmojisExcept(text, Arrays.asList(emojisToKeep)); - } - /** * Replaces all emojis in the text with the given replacement string. * @@ -435,6 +448,18 @@ public static String replaceEmojis(final String text, final String replacementSt return replaceEmojis(text, emoji -> replacementString, emojisToReplace); } + /** + * Replaces the given emojis with the given replacement string. + * + * @param text The text to replace emojis from. + * @param replacementString The replacement string. + * @param emojisToReplace The emojis to replace. + * @return The text with the given emojis replaced. + */ + public static String replaceEmojis(final String text, final String replacementString, final Emoji... emojisToReplace) { + return replaceEmojis(text, emoji -> replacementString, Arrays.asList(emojisToReplace)); + } + /** * Replaces all emojis in the text with the given replacement function. * @@ -446,8 +471,6 @@ public static String replaceEmojis(final String text, final String replacementSt public static String replaceEmojis(final String text, Function replacementFunction, final Collection emojisToReplace) { if (isStringNullOrEmpty(text)) return ""; - final LinkedHashMap> FIRST_CODEPOINT_TO_EMOJIS_ORDER_CODEPOINT_LENGTH_DESCENDING = emojisToReplace.stream().sorted(EMOJI_CODEPOINT_COMPARATOR).collect(getEmojiLinkedHashMapCollector()); - final int[] textCodePointsArray = text.codePoints().toArray(); final long textCodePointsLength = textCodePointsArray.length; @@ -458,7 +481,7 @@ public static String replaceEmojis(final String text, Function re final int currentCodepoint = textCodePointsArray[textIndex]; sb.appendCodePoint(currentCodepoint); - final List emojisByCodePoint = FIRST_CODEPOINT_TO_EMOJIS_ORDER_CODEPOINT_LENGTH_DESCENDING.get(currentCodepoint); + final List emojisByCodePoint = EMOJI_FIRST_CODEPOINT_TO_EMOJIS_ORDER_CODEPOINT_LENGTH_DESCENDING.get(currentCodepoint); if (emojisByCodePoint == null) continue; for (final Emoji emoji : emojisByCodePoint) { final int[] emojiCodePointsArray = emoji.getEmoji().codePoints().toArray(); @@ -468,17 +491,22 @@ public static String replaceEmojis(final String text, Function re continue; } - for (int i = 0; i < emojiCodePointsLength; i++) { - if (textCodePointsArray[textIndex + i] != emojiCodePointsArray[i]) { + for (int emojiCodePointIndex = 0; emojiCodePointIndex < emojiCodePointsLength; emojiCodePointIndex++) { + //break out because the emoji is not the same + if (textCodePointsArray[textIndex + emojiCodePointIndex] != emojiCodePointsArray[emojiCodePointIndex]) { break; } - if (i == emojiCodePointsLength - 1) { - //Does the same but is slower apparently - //sb.replace(sb.length() - Character.charCount(currentCodepoint), sb.length(), replacementString); - sb.delete(sb.length() - Character.charCount(currentCodepoint), sb.length()); - sb.append(replacementFunction.apply(emoji)); + if (emojiCodePointIndex == (emojiCodePointsLength - 1)) { textIndex += emojiCodePointsLength - 1; + sb.delete(sb.length() - Character.charCount(currentCodepoint), sb.length()); + + if (emojisToReplace.contains(emoji)) { + sb.append(replacementFunction.apply(emoji)); + } else { + sb.append(emoji.getEmoji()); + } + continue nextTextIteration; } } @@ -488,6 +516,18 @@ public static String replaceEmojis(final String text, Function re return sb.toString(); } + /** + * Replaces all emojis in the text with the given replacement function. + * + * @param text The text to replace emojis from. + * @param replacementFunction The replacement function. + * @param emojisToReplace The emojis to replace. + * @return The text with all emojis replaced. + */ + public static String replaceEmojis(final String text, Function replacementFunction, final Emoji... emojisToReplace) { + return replaceEmojis(text, replacementFunction, Arrays.asList(emojisToReplace)); + } + private static boolean isStringNullOrEmpty(final String string) { return null == string || string.isEmpty(); } diff --git a/lib/src/test/java/net/fellbaum/jemoji/EmojiManagerTest.java b/lib/src/test/java/net/fellbaum/jemoji/EmojiManagerTest.java index be0d186..eaba8b7 100644 --- a/lib/src/test/java/net/fellbaum/jemoji/EmojiManagerTest.java +++ b/lib/src/test/java/net/fellbaum/jemoji/EmojiManagerTest.java @@ -1,38 +1,35 @@ package net.fellbaum.jemoji; -import org.junit.Assert; import org.junit.Test; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; +import static org.junit.Assert.*; + public class EmojiManagerTest { public static final String ALL_EMOJIS_STRING = EmojiManager.getAllEmojisLengthDescending().stream().map(Emoji::getEmoji).collect(Collectors.joining()); - private static final String SIMPLE_EMOJI_STRING = "Hello ❤️ World"; + private static final String SIMPLE_EMOJI_STRING = "Hello ❤️ ❤ ❤❤️ World"; @Test public void extractEmojisInOrder() { List emojis = EmojiManager.extractEmojisInOrder(ALL_EMOJIS_STRING + ALL_EMOJIS_STRING); - Assert.assertEquals(EmojiManager.getAllEmojisLengthDescending().size() * 2, emojis.size()); + assertEquals(EmojiManager.getAllEmojisLengthDescending().size() * 2, emojis.size()); List allEmojis = new ArrayList<>(EmojiManager.getAllEmojisLengthDescending()); allEmojis.addAll(EmojiManager.getAllEmojisLengthDescending()); - Assert.assertEquals(allEmojis, emojis); + assertEquals(allEmojis, emojis); } @Test public void extractEmojis() { Set emojis = EmojiManager.extractEmojis(ALL_EMOJIS_STRING + ALL_EMOJIS_STRING); - Assert.assertEquals(EmojiManager.getAllEmojisLengthDescending().size(), emojis.size()); + assertEquals(EmojiManager.getAllEmojisLengthDescending().size(), emojis.size()); Set allEmojis = EmojiManager.getAllEmojis(); - Assert.assertEquals(allEmojis, emojis); + assertEquals(allEmojis, emojis); } @Test @@ -40,15 +37,15 @@ public void getEmoji() { String emojiString = "👍"; Optional emoji = EmojiManager.getEmoji(emojiString); - Assert.assertTrue(emoji.isPresent()); - Assert.assertEquals(emojiString, emoji.get().getEmoji()); + assertTrue(emoji.isPresent()); + assertEquals(emojiString, emoji.orElseThrow(RuntimeException::new).getEmoji()); } @Test public void isEmoji() { String emojiString = "\uD83D\uDC4D"; - Assert.assertTrue(EmojiManager.isEmoji(emojiString)); + assertTrue(EmojiManager.isEmoji(emojiString)); } @Test @@ -56,8 +53,8 @@ public void getByAlias() { String alias = "smile"; Optional emoji = EmojiManager.getByAlias(alias); - Assert.assertTrue(emoji.isPresent()); - Assert.assertEquals("😄", emoji.get().getEmoji()); + assertTrue(emoji.isPresent()); + assertEquals("😄", emoji.orElseThrow(RuntimeException::new).getEmoji()); } @Test @@ -65,37 +62,43 @@ public void getByAliasWithColon() { String alias = ":smile:"; Optional emoji = EmojiManager.getByAlias(alias); - Assert.assertTrue(emoji.isPresent()); - Assert.assertEquals("😄", emoji.get().getEmoji()); + assertTrue(emoji.isPresent()); + assertEquals("😄", emoji.orElseThrow(RuntimeException::new).getEmoji()); } @Test public void containsEmoji() { - Assert.assertTrue(EmojiManager.containsEmoji(SIMPLE_EMOJI_STRING)); + assertTrue(EmojiManager.containsEmoji(SIMPLE_EMOJI_STRING)); } @Test public void removeEmojis() { - Assert.assertEquals("Hello World", EmojiManager.removeAllEmojis(SIMPLE_EMOJI_STRING)); + assertEquals("Hello World", EmojiManager.removeAllEmojis(SIMPLE_EMOJI_STRING)); } @Test public void removeAllEmojisExcept() { - Assert.assertEquals("Hello ❤️ World", EmojiManager.removeAllEmojisExcept(SIMPLE_EMOJI_STRING + "👍", Collections.singletonList(EmojiManager.getEmoji("❤️").get()))); + assertEquals("Hello ❤️ ❤️ World", EmojiManager.removeAllEmojisExcept(SIMPLE_EMOJI_STRING + "👍", EmojiManager.getEmoji("❤️").orElseThrow(RuntimeException::new))); } @Test public void replaceEmojis() { - Assert.assertEquals("Hello :heart: World", EmojiManager.replaceEmojis(SIMPLE_EMOJI_STRING, ":heart:", Collections.singletonList(EmojiManager.getEmoji("❤️").get()))); + assertEquals("Hello :heart: ❤ ❤:heart: World", EmojiManager.replaceEmojis(SIMPLE_EMOJI_STRING, ":heart:", EmojiManager.getEmoji("❤️").orElseThrow(RuntimeException::new))); + } + + @Test + public void replaceOnlyUnqualifiedEmoji() { + assertEquals("Hello ❤️ :heart: :heart:❤️ World", EmojiManager.replaceEmojis(SIMPLE_EMOJI_STRING, ":heart:", EmojiManager.getEmoji("❤").orElseThrow(RuntimeException::new))); } @Test public void replaceAllEmojis() { - Assert.assertEquals("Hello something World something something something", EmojiManager.replaceAllEmojis(SIMPLE_EMOJI_STRING + " 👍 👨🏿‍🦱 😊", "something")); + assertEquals("Hello something something somethingsomething World something something something", EmojiManager.replaceAllEmojis(SIMPLE_EMOJI_STRING + " 👍 👨🏿‍🦱 😊", "something")); } @Test public void replaceAllEmojisFunction() { - Assert.assertEquals("Hello SMILEYS_AND_EMOTION World PEOPLE_AND_BODY PEOPLE_AND_BODY SMILEYS_AND_EMOTION", EmojiManager.replaceAllEmojis(SIMPLE_EMOJI_STRING + " 👍 👨🏿‍🦱 😊", emoji -> emoji.getGroup().toString())); + assertEquals("Hello SMILEYS_AND_EMOTION SMILEYS_AND_EMOTION SMILEYS_AND_EMOTIONSMILEYS_AND_EMOTION World PEOPLE_AND_BODY PEOPLE_AND_BODY SMILEYS_AND_EMOTION", EmojiManager.replaceAllEmojis(SIMPLE_EMOJI_STRING + " 👍 👨🏿‍🦱 😊", emoji -> emoji.getGroup().toString())); } + } \ No newline at end of file