[译]Flutter Favorite 之字符操作库 characters

579 阅读3分钟

原文: characters | Dart Package (flutter-io.cn)

译时版本: 1.2.1


Characters 是可视为  用户感知的字符 序列的字符串,即熟知的 [Unicode (扩展) 字符集]

Characters 类可访问字符串中的单个字符,也提供使用 CharacterRange 在范围内向前和向后导航的方法。

Unicode 字符和表示

这里没有 纯文本 的东西。

计算机只认识数字,所以任何 “文本” 在计算机中都表示为数字,在内存中保存为字节。

这些字节的意思通过解释层提供,编译为计算机显示在屏幕上的象形文字

抽象Dart 类型用法示例
BytesByteBuffer, Uint8List物理布局:内存或网络通信。file.readAsBytesSync()
码单位Uint8List (UTF‑8) Uint16List, String (UTF‑16)内存中为码点编码的标准格式。使用 一个字节 (UTF‑8)或 多个字节(UTF‑16)存储在内存中。一个或多个码单位对一个码点进行编码。string.codeUnits string.codeUnitAt(index) utf8.encode(string)
码点RunesUnicode 意义上的单位string.runes
字符集Characters人类感知的字符。一个或多个码点string.characters
象形文字字符集的可视化渲染。print(string)

一个Dart String 是一个 UTF-16 码单位的序列,就像 JavaScript 和 Java 的字符串。运行时系统依赖底层的物理表示。

当需要操作用户正在查看或输入的文本时,只表示纯字符串是不够的,因为字符串操作不会在字符集级别上进行处理。

例如,要把一段文本缩略为前15个字符或者象形文字,像 "A 🇬🇧 text in English" 这样的字符串,当数字符时会缩略为 "A 🇬🇧 text in Eng… ", 但是如果使用 String 操作数码单位时,就会是 "A 🇬🇧 text in …" 。

无论何时,当需要在字符级别操作字符串时,都就该使用 Characters 类型,而不是使用 String 类的方法。

Characters 类

Characters 类暴露了一个字符串作为字符集的序列。 所有针对 Characters 的操作都是在操作整个字符集,所以它避免了把基于 String 类的固有码单元的合成字符或颜文字分割开的风险。

可以使用 Characters(string) 或扩展的 getter string.characters 获取一个字符串的 Characters 对象。

在它的内核里,该类是一个 Iterable<String> (字符串的迭代器),这里面的元素字符串都是单个字符集。这可以实现按次序读取原始字符串里的单个字符集。

最重要的是,它还有一些 String 操作的一些镜像操作,不是基于索引、码单位或码点的,如 startsWith 或 replaceAll。这些和 String 操作有一些不同。例如, replace 方法只接收字符作为模式。正则表达式不会识别字符集,所以它们不能安全地用于字符序列。

字符集在底层表示上有多种长度,所以对于 Characters 序列的操作不能是基于索引的。 取而代之的是由大大强化的 Characters.iterator提供的 CharacterRange 迭代器 。它可以向前和向后移动,,它能够跨越一个字符集的 范围 。

可用于完整 Characters 的大多数操作也用于字符集的 CharacterRange 范围。 该范围可以多种方式收缩、扩展或移动,而不局限于使用 moveNext 移动到下一个字符集。

例如:

// 使用字符串下标。
String firstTagString(String source) {
  var start = string.indexOf("<") + 1;
  if (start > 0) {
    var end = string.indexOf(">", start);
    if (end >= 0) {
	    return string.substring(start, end);
    }
  }
  return null;
}

// 使用 CharacterRange 操作
Characters firstTagCharacters(Characters source) {
  var range = source.findFirst("<".characters);
  if (range != null && range.moveUntil(">".characters)) {
    return range.currentCharacters;
  }
  return null;
}