【问题标题】:How to reverse strings that contain surrogate pairs in Dart?如何在 Dart 中反转包含代理对的字符串?
【发布时间】:2019-10-13 03:43:08
【问题描述】:

我正在使用 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 编程语言反转可能包含代理对的字符串?

【问题讨论】:

    标签: string flutter unicode dart surrogate-pairs


    【解决方案1】:

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

    【讨论】:

    • 哦,我真希望它会比这更简单一些。源代码在 2300 LOC 左右...
    • 不幸的是,看起来没有办法解决这个问题。仅供参考,也在 GitHub 上问过这个问题github.com/dart-lang/sdk/issues/38854
    • 没有简单的方法可以找到字素簇的边界。你需要知道在 15 个中,每个代码点属于哪个类别,并且有 0x10FFFF 代码点。然后你必须有效地在这些类别上模拟一个有限状态自动机,这样你就可以正确地在挥舞旗帜和彩虹之间打破,但不能在挥舞旗帜、零宽度连接器和彩虹之间打破。这样做有正确的方法,也有许多错误的方法,但没有一种简单和正确的方法。
    【解决方案2】:

    Dart 2.7 引入了supports grapheme 集群感知操作的新包。该包名为characterscharacters 是表示为 Unicode 扩展字素簇的字符包。

    Dart 的标准 String 类使用 UTF-16 编码。这是编程语言中的常见选择,尤其是那些支持在设备和网络上本地运行的语言。

    UTF-16 字符串通常运行良好,并且编码对开发人员是透明的。但是,在处理字符串时,尤其是在处理用户输入的字符串时,您可能会遇到用户感知为字符的内容与 UTF-16 中编码为代码单元的内容之间的差异

    来源:"Announcing Dart 2.7: A safer, more expressive Dart" by Michael Thomsen,“安全子字符串处理”部分

    该软件包还将帮助您按照本地程序员所期望的方式使用表情符号反转字符串。

    使用简单的Strings,你会发现问题:

    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 团队维护。

    【讨论】:

      猜你喜欢
      • 2014-04-02
      • 2014-02-26
      • 2010-11-23
      • 2012-12-30
      • 2021-01-16
      • 2016-11-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-23
      相关资源
      最近更新 更多