You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中实现非ASCII字符与普通文本的排序?

Dart中特殊装饰性字母的排序解决方案

问题原因

你遇到的这些字符属于Unicode装饰性字母变体(如数学斜体、粗体、空心体等),它们是独立的Unicode码位,并非普通拉丁字母的大小写变体。常规的toLowerCase().compareTo()方法仅能处理普通A-Z/a-z字符的大小写转换,无法将这些特殊变体映射到对应的基础拉丁字母,导致排序逻辑失效。

解决方案

核心思路是先将所有装饰性字母规范化为普通拉丁字母,再执行大小写不敏感排序。推荐通过Unicode兼容性分解(NFKD)剥离装饰标记,保留基础字符。

步骤1:添加依赖

在pubspec.yaml中引入unicode包以支持Unicode规范化:

dependencies:
  unicode: ^0.3.1

步骤2:实现字符规范化函数

编写函数将特殊字符转换为普通拉丁字母:

import 'package:unicode/unicode.dart';

// 将装饰性字母转换为普通小写拉丁字母
String normalizeDecoratedChars(String input) {
  // 执行NFKD规范化,将装饰性字符分解为基础字母+装饰标记
  final normalized = input.normalize(NFKD);
  final buffer = StringBuffer();
  
  for (final rune in normalized.runes) {
    // 仅保留普通拉丁字母(A-Z, a-z)
    if ((rune >= 0x0041 && rune <= 0x005A) || (rune >= 0x0061 && rune <= 0x007A)) {
      buffer.writeCharCode(rune);
    }
    // 自动过滤装饰标记和非字母字符
  }
  
  return buffer.toString().toLowerCase();
}

步骤3:执行排序

使用规范化后的字符串进行排序:

void main() {
  final names = [
    '𝔦𝔠𝔦𝔞𝔩𝔞',
    '𝓕𝓪𝓴𝓷𝓬𝓻𝓪',
    '𝗺𝗹𝗲𝗖𝗹𝗮𝗿𝗮',
    '𝙖𝙨𝙡𝙖𝙜𝙖𝙈𝙮',
    '𝖧𝗋𝗂𝖾',
    '𝑮𝒂𝒍𝒍𝒆𝒂',
    '𝐿𝑢𝑛𝑎',
    '𝐃𝐡𝐢𝐚',
    '𝕠ℝ𝕒𝕥𝕧𝕒𝕠𝕜𝕠'
  ];

  // 按规范化后的字母排序
  names.sort((a, b) {
    final normA = normalizeDecoratedChars(a);
    final normB = normalizeDecoratedChars(b);
    return normA.compareTo(normB);
  });

  // 输出排序结果
  print(names);
}

验证结果

执行后会得到按普通字母顺序排列的结果:

[𝙖𝙨𝙡𝙖𝙜𝙖𝙈𝙮, 𝐃𝐡𝐢𝐚, 𝓕𝓪𝓴𝓷𝓬𝓻𝓪, 𝑮𝒂𝒍𝒍𝒆𝒂, 𝖧𝗋𝗂𝖾, 𝔦𝔠𝔦𝔞𝔩𝔞, 𝐿𝑢𝑛𝑎, 𝗺𝗹𝗲𝗖𝗹𝗮𝗿𝗮, 𝕠ℝ𝕒𝕥𝕧𝕒𝕠𝕜𝕠]

无依赖替代方案(手动映射)

如果不想引入第三方包,可以针对常见的装饰性字母范围手动映射(仅示例部分范围,需根据需求扩展):

String normalizeDecoratedChars(String input) {
  final buffer = StringBuffer();
  for (final rune in input.runes) {
    // 数学粗体大写字母(U+1D400-U+1D433)→ 普通大写字母
    if (rune >= 0x1D400 && rune <= 0x1D433) {
      buffer.writeCharCode(rune - 0x1D3BF);
    }
    // 数学粗体小写字母(U+1D41A-U+1D44D)→ 普通小写字母
    else if (rune >= 0x1D41A && rune <= 0x1D44D) {
      buffer.writeCharCode(rune - 0x1D3B9);
    }
    // 数学斜体大写字母(U+1D468-U+1D49B)→ 普通大写字母
    else if (rune >= 0x1D468 && rune <= 0x1D49B) {
      buffer.writeCharCode(rune - 0x1D427);
    }
    // 数学斜体小写字母(U+1D482-U+1D4B5)→ 普通小写字母
    else if (rune >= 0x1D482 && rune <= 0x1D4B5) {
      buffer.writeCharCode(rune - 0x1D421);
    }
    // 保留普通字母
    else if ((rune >= 0x0041 && rune <= 0x005A) || (rune >= 0x0061 && rune <= 0x007A)) {
      buffer.writeCharCode(rune);
    }
  }
  return buffer.toString().toLowerCase();
}

内容的提问来源于stack exchange,提问作者TSR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:17:16