If try to use information about Unicode mapping sequences, you can get a more or less normal result.
import 'package:sequence_processor/sequence_processor.dart';import 'package:unicode/decomposers/canonical.dart';import 'package:unicode/emoji/emoji.dart';void main(List<String> args) { var str = 'hello🇵🇬你们😀😀👨👩👦'; print('"$str"'); while (str.isNotEmpty) { str = myBackspace(str); print('"$str"'); } str = 'I 💗 you! ❤️🔥'; print('"$str"'); while (str.isNotEmpty) { str = myBackspace(str); print('"$str"'); } str = 'Amélie'; print('"$str"'); while (str.isNotEmpty) { str = myBackspace(str); print('"$str"'); }}// Should be stored in a static member for performance reasons.final _processor = () { final emojis = getUnicodeEmojiList(); final processor = SequenceProcessor<int, Object>(); for (final emoji in emojis) { processor.addSequence(emoji.codePoints, emoji); } const decomposer = CanonicalDecomposer(); final mappingList = decomposer.getMappingList(); for (var i = 0; i < mappingList.length; i++) { final mapping = mappingList[i]; final sequence = mapping.$2; if (sequence.length > 1) { if (!processor.hasSequence(sequence)) { processor.addSequence(mapping.$2, mapping.$1); } } } return processor;}();String myBackspace(String text) { if (text.isEmpty) { return ''; } final result = _processor.process(text.runes.toList()); if (result.isEmpty) { return ''; } return result .take(result.length - 1) .map((e) => e.data == null ? String.fromCharCode(e.element!) : String.fromCharCodes(e.sequence!)) .join();}
Output:
"hello🇵🇬你们😀😀👨👩👦""hello🇵🇬你们😀😀""hello🇵🇬你们😀""hello🇵🇬你们""hello🇵🇬你""hello🇵🇬""hello""hell""hel""he""h""""I 💗 you! ❤️🔥""I 💗 you! ❤️🔥""I 💗 you! ""I 💗 you!""I 💗 you""I 💗 yo""I 💗 y""I 💗""I 💗""I ""I""""Amélie""Améli""Amél""Amé""Am""A"""