flutter 如何在Dart中反转包含代理项对的字符串?

vltsax25  于 2023-04-13  发布在  Flutter
关注(0)|答案(3)|浏览(113)

我使用Dart玩算法,当我实际上遵循TDD时,我意识到我的代码有一些限制。
我试图将字符串反转作为面试问题的一部分,但我无法正确地反转代理对。

const simple = 'abc';
const emoji = '🍎🍏🐛';
const surrogate = '👮🏽‍♂️👩🏿‍💻';

String rev(String s) {
    return String.fromCharCodes(s.runes.toList().reversed);
}

void main() {
    print(simple);
    print(rev(simple));
    print(emoji);
    print(rev(emoji));
    print(surrogate);
    print(rev(surrogate));
}

输出:

abc
cba
🍎🍏🐛
🐛🍏🍎
👮🏽‍♂️👩🏿‍💻
💻‍🏿👩️♂‍🏽👮

你可以看到,简单的表情符号被正确地反转了,因为我使用的是runes,而不是简单地执行s.split('').toList().reversed.join('');,但是代理对被错误地反转了。

如何使用Dart编程语言反转可能包含代理项对的字符串?

xmakbtuz

xmakbtuz1#

当反转字符串时,必须对字素进行操作,而不是字符或代码单位。使用grapheme_splitter

cbeh67ev

cbeh67ev2#

Dart 2.7引入了一个新的包,supports grapheme cluster-aware操作。该包被称为characterscharacters是一个表示为Unicode扩展grapheme clusters的字符包。
Dart的标准String类使用UTF-16编码。这是编程语言中的常见选择,特别是那些支持在设备和Web上本地运行的语言。
UTF-16字符串通常工作良好,编码对开发人员是透明的。但是,当操作字符串时,特别是当操作用户输入的字符串时,您可能会遇到用户认为的字符和UTF-16编码的代码单元之间的差异

该软件包还将帮助您以本机程序员期望的方式使用emoji反转字符串。
使用简单的String s,您会发现问题:

String hi = 'Hi 🇩🇰';
print('String.length: ${hi.length}');
// Prints 7; would expect 4

关于characters

String hi = 'Hi 🇩🇰';
print(hi.characters.length);
// Prints 4
print(hi.characters.last);
// Prints 🇩🇰

值得一看的是source code of the characters package,它远不简单,但看起来比grapheme_splitter更容易消化和更好地记录。characters包也由Dart团队维护。

yptwkmov

yptwkmov3#

在名为reversedString上创建extension

extension on String {
  /// Reverse the string

  String get reversed =>
      GraphemeSplitter().splitGraphemes(this).toList().reversed.join();
}

要添加GraphemeSplitter类,请安装grapheme_splitter包:

dart pub add grapheme_splitter

示例程序:

import "package:grapheme_splitter/grapheme_splitter.dart";
import "dart:io";

void main(final List<String> $) async {
  test();
}

void test() async {
  final Writer writer = Writer();

  const simple = 'abc';

  const emoji = '🍎🍏🐛';

  const surrogate = '👮🏽‍♂️👩🏿‍💻';

  const hell = "Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘";

  const nightmare = "🌷🎁💩😜👍🏳️‍🌈";

  await writer.print(simple);
  await writer.print(emoji);
  await writer.print(surrogate);
  await writer.print(hell);
  await writer.print(nightmare);

  await writer.print(simple.reversed);
  await writer.print(emoji.reversed);
  await writer.print(surrogate.reversed);
  await writer.print(hell.reversed);
  await writer.print(nightmare.reversed);
}

class Writer {
  final String filePath;
  final File file;

  Writer({this.filePath = "./data.dat"})
      : file = File(filePath)
          ..writeAsString(
              ""); // If File exits lets truncate it

  print(final Object data) async {
    await file.writeAsString("${data.toString()}\n",
        mode: FileMode.append); // Appends to the above file
  }
}

extension on String {
  /// Reverse the string

  String get reversed =>
      GraphemeSplitter().splitGraphemes(this).toList().reversed.join();
}

data.dat 文件输出

abc
🍎🍏🐛
👮🏽‍♂️👩🏿‍💻
Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘
🌷🎁💩😜👍🏳️‍🌈
cba
🐛🍏🍎
👩🏿‍💻👮🏽‍♂️
Ǫ̵̹̻̝̳͂̌̌͘G̴̻͈͍͔̹̑͗̎̅͛́L̠ͨͧͩ͘A̴̵̜̰͔ͫ͗͢Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍
🏳️‍🌈👍😜💩🎁🌷

输出显示在 file 中而不是terminal中,因为大多数terminal无法正确呈现这些字符。

相关问题