You fell into an often-overlooked trap, which makes your program useless to most of the world. It assumes that one char
is one "character" (as users would understand it). Here's where that goes wrong:
🇧🇬
🇬🇧
Anagrams
The first input is the flag of Bulgaria, and the second is the flag of Great Britain. You see, there isn't actually a dedicated Unicode code point for every flag. Instead, there are 26 regional indicator symbols, one for each of the 26 English letters. These are combined into ISO 3166-2 2-letter country codes. In this case, "[B][G]"
and "[G][B]"
. It's then the system's responsibility to identify these country codes, and present a single glyph which shows the latest flag for that country code.
Your program considers these to be anagrams. It would fail in similar spectacular ways for skin-tone-modified emojis, family emojis, many non-latin alphabets (including popular ones like Chinese).
The solution is to operate on the level of "Unicode Extended Grapheme Clusters" rather than chars
(which model Unicode scalars). This is the closest thing to a human's understanding of "characters", accounting for things like emoji families, flags, characters with accent modifiers applied to them, and so on. It's not a perfect match, but it's pretty close.
This code snippet from this answer looks like a pretty promising way to decompose a string into its constituent EGCs:
String[] extendedGraphemeClusters = inputString.codePoints()
.mapToObj(cp -> new String(Character.toChars(cp)))
.toArray(size -> new String[size]);
You could then use this extendedGraphemeClusters
array of strings (where each string is really just an EGC) as the input to the various algorithms discussed in the other answers. E.g. you can use that array with the sorting approach you used originally. Rather than sorting the characters with the input string, you would sort the strings (modeling EGCs) in the array (which models the EGCs of the input string).
You could also use the HashMap
based approach with it, just the same.