string

SKILL.md

仓颉标准库 String 类型 Skill

1. 概述

String 是仓颉核心包 std.core 中的 struct 类型,无需导入 即可直接使用。

  • 不可变值类型(赋值产生副本)
  • 仅支持 UTF-8 编码,最大长度为 UInt32.Max(约 4 GB)
  • 实现接口:Collection<Byte>Comparable<String>HashableToString

注意String 实现了 Collection<Byte>for (b in s) 迭代的是 UTF-8 字节(Byte / UInt8),而非字符。若要按字符迭代,请使用 for (r in s.runes())


2. 构造

// 空字符串
let s1 = ""
let s2 = String()
let s3 = String.empty           // 静态常量

// 字符串字面量
let s4 = "Hello, 仓颉!"

// 多行字符串(三引号)
let s5 = """
    第一行
    第二行
    """

// 从 Rune 数组构造
let runes: Array<Rune> = [r'H', r'i']
let s6 = String(runes)          // "Hi"

// 从 Rune 集合构造
let s7 = String(someRuneCollection)

// 从 UTF-8 字节数组构造
let bytes: Array<UInt8> = [72, 101, 108, 108, 111]
let s8 = String.fromUtf8(bytes) // "Hello"(会校验 UTF-8 合法性)

3. 属性

属性 类型 说明
size Int64 UTF-8 编码字节长度(不是字符数
let s = "Hello"
println(s.size)     // 5

let s2 = "你好"
println(s2.size)    // 6(每个汉字 3 字节 UTF-8)

4. 静态方法

4.1 join — 拼接字符串数组

static func join(strArr: Array<String>, delimiter!: String = String.empty): String
let arr = ["I", "like", "Cangjie"]
let s = String.join(arr, delimiter: " ")
println(s) // "I like Cangjie"

let csv = String.join(["a", "b", "c"], delimiter: ",")
println(csv) // "a,b,c"

4.2 fromUtf8 — 从 UTF-8 字节数组构造

static func fromUtf8(utf8Data: Array<UInt8>): String
  • 校验字节数组是否为合法 UTF-8,非法则抛出 IllegalArgumentException
let bytes: Array<UInt8> = [72, 101, 108, 108, 111]
let s = String.fromUtf8(bytes) // "Hello"

4.3 fromUtf8Unchecked — 不校验构造(unsafe)

static func fromUtf8Unchecked(utf8Data: Array<UInt8>): String
  • 不校验 UTF-8 合法性,性能更好但使用不当会导致未定义行为

4.4 checkUtf8Encoding — 校验 UTF-8 合法性

static func checkUtf8Encoding(data: Array<UInt8>): Bool
let valid = String.checkUtf8Encoding([72, 101]) // true
let invalid = String.checkUtf8Encoding([0xFF, 0xFE]) // false

5. 搜索与检查

5.1 contains — 包含子串

func contains(str: String): Bool
"Hello World".contains("World") // true
"Hello World".contains("world") // false(大小写敏感)

5.2 startsWith / endsWith — 前缀/后缀检查

func startsWith(prefix: String): Bool
func endsWith(suffix: String): Bool
"hello.cj".startsWith("hello") // true
"hello.cj".endsWith(".cj")     // true

5.3 indexOf — 查找首次出现位置

func indexOf(b: Byte): Option<Int64>
func indexOf(b: Byte, fromIndex: Int64): Option<Int64>
func indexOf(str: String): Option<Int64>
func indexOf(str: String, fromIndex: Int64): Option<Int64>
let s = "Hello World"
s.indexOf("World")     // Some(6)
s.indexOf("xyz")       // None
s.indexOf("l")         // Some(2)
s.indexOf("l", 3)      // Some(3)  — 从索引 3 开始搜索

5.4 lastIndexOf — 查找最后出现位置

func lastIndexOf(b: Byte): Option<Int64>
func lastIndexOf(b: Byte, fromIndex: Int64): Option<Int64>
func lastIndexOf(str: String): Option<Int64>
func lastIndexOf(str: String, fromIndex: Int64): Option<Int64>
"abcabc".lastIndexOf("abc") // Some(3)

5.5 count — 统计子串出现次数

func count(str: String): Int64
"abababab".count("ab") // 4

5.6 isEmpty / isAscii / isAsciiBlank

func isEmpty(): Bool        // 是否为空串
func isAscii(): Bool        // 是否全为 ASCII 字符
func isAsciiBlank(): Bool   // 是否为空串或仅含 ASCII 空白字符

6. 替换与删除

6.1 replace — 替换所有匹配子串

func replace(old: String, new: String): String
"aabbcc".replace("bb", "XX") // "aaXXcc"
"aaa".replace("a", "bb")     // "bbbbbb"

6.2 removePrefix / removeSuffix — 删除前缀/后缀

func removePrefix(prefix: String): String
func removeSuffix(suffix: String): String
  • 如果字符串不以指定前缀/后缀开头/结尾,返回原字符串
"HelloWorld".removePrefix("Hello") // "World"
"HelloWorld".removeSuffix("World") // "Hello"
"HelloWorld".removePrefix("xyz")   // "HelloWorld"

7. 分割

7.1 split — 按分隔符分割

func split(str: String, removeEmpty!: Bool = false): Array<String>
func split(str: String, maxSplits: Int64, removeEmpty!: Bool = false): Array<String>
"a,b,,c".split(",")                    // ["a", "b", "", "c"]
"a,b,,c".split(",", removeEmpty: true) // ["a", "b", "c"]
"a,b,c,d".split(",", 2)               // ["a", "b", "c,d"]  — 最多分割 2 次

7.2 lazySplit — 惰性分割(返回迭代器)

func lazySplit(str: String, removeEmpty!: Bool = false): Iterator<String>
func lazySplit(str: String, maxSplits: Int64, removeEmpty!: Bool = false): Iterator<String>
  • split 功能相同,但返回 Iterator<String>,适合处理大字符串时避免一次性分配

7.3 lines — 按行分割

func lines(): Iterator<String>
let text = "line1\nline2\nline3"
for (line in text.lines()) {
    println(line)
}
// 输出:
// line1
// line2
// line3

8. 裁剪(Trim)

8.1 ASCII 空白裁剪

func trimAscii(): String       // 两端裁剪 ASCII 空白
func trimAsciiStart(): String  // 裁剪前导 ASCII 空白
func trimAsciiEnd(): String    // 裁剪尾部 ASCII 空白
"  hello  ".trimAscii()      // "hello"
"  hello  ".trimAsciiStart() // "hello  "
"  hello  ".trimAsciiEnd()   // "  hello"

8.2 自定义裁剪

// 按 Rune 数组裁剪(移除集合中的任意字符)
func trimStart(chars: Array<Rune>): String
func trimEnd(chars: Array<Rune>): String

// 按字符串裁剪(移除前缀/后缀子串的重复出现)
func trimStart(str: String): String
func trimEnd(str: String): String

// 按谓词裁剪(移除满足条件的字符)
func trimStart(predicate: (Rune) -> Bool): String
func trimEnd(predicate: (Rune) -> Bool): String
"xxxHelloxxx".trimStart([r'x'])              // "Helloxxx"
"xxxHelloxxx".trimEnd([r'x'])                // "xxxHello"
"123abc456".trimStart { r => r >= r'0' && r <= r'9' } // "abc456"

9. 填充(Pad)

func padStart(totalWidth: Int64, padding!: String = " "): String
func padEnd(totalWidth: Int64, padding!: String = " "): String
  • totalWidth 为目标字节宽度
  • 如果原字符串长度已 ≥ totalWidth,返回原字符串
"42".padStart(6)           // "    42"
"42".padStart(6, padding: "0") // "000042"
"42".padEnd(6)             // "42    "
"42".padEnd(6, padding: ".")  // "42...."

10. 大小写转换

func toAsciiLower(): String   // 转小写(仅 ASCII 字母)
func toAsciiUpper(): String   // 转大写(仅 ASCII 字母)
func toAsciiTitle(): String   // 首字母大写(仅 ASCII 字母)
"Hello World".toAsciiLower() // "hello world"
"Hello World".toAsciiUpper() // "HELLO WORLD"
"hello world".toAsciiTitle() // "Hello World"

11. 比较

func compare(other: String): Ordering   // 字典序比较,返回 Ordering.LT/EQ/GT
func equalsIgnoreAsciiCase(other: String): Bool  // 忽略 ASCII 大小写比较
"abc".compare("abd")                     // Ordering.LT
"Hello".equalsIgnoreAsciiCase("hello")   // true

运算符比较

"abc" == "abc"  // true
"abc" != "def"  // true
"abc" < "abd"   // true(字典序)
"abc" <= "abc"  // true
"abd" > "abc"   // true
"abd" >= "abc"  // true

12. 拼接与重复

12.1 + 运算符 — 字符串拼接

let s = "Hello" + ", " + "World!" // "Hello, World!"

12.2 * 运算符 — 重复

let s = "ab" * 3  // "ababab"
let line = "-" * 20  // "--------------------"

12.3 字符串插值 "${expr}"

let name = "Cangjie"
let age = 3
let s = "Name: ${name}, Age: ${age}" // "Name: Cangjie, Age: 3"

12.4 String.join — 拼接数组

let parts = ["2024", "06", "15"]
let date = String.join(parts, delimiter: "-") // "2024-06-15"

12.5 StringBuilder — 高效拼接

大量拼接时建议使用 StringBuilder

let sb = StringBuilder()
sb.append("Hello")
sb.append(", ")
sb.append("World!")
let result = sb.toString() // "Hello, World!"

13. 转换

13.1 转为字节数组

func toArray(): Array<Byte>      // 返回 UTF-8 字节数组(拷贝)
func rawData(): Array<Byte>      // 返回内部原始数据引用(unsafe)
let bytes = "Hi".toArray()   // [72, 105]

13.2 转为 Rune 数组

func toRuneArray(): Array<Rune>
let runes = "Hi你".toRuneArray() // [r'H', r'i', r'你']

13.3 迭代

func iterator(): Iterator<Byte>   // 按字节迭代
func runes(): Iterator<Rune>      // 按字符(Rune)迭代
// 按字符迭代(推荐)
for (r in "Hello 仓颉".runes()) {
    print(r)
}

// 按字节迭代
for (b in "Hello") {
    print(b)  // 输出 UTF-8 字节值
}

13.4 toString

func toString(): String  // 返回自身

13.5 hashCode

func hashCode(): Int64  // 返回哈希值,可用于 HashMap 等

14. 下标访问与切片

14.1 按字节索引

let s = "Hello"
let b: Byte = s[0]         // 72 (H 的 UTF-8 编码)
let opt = s.get(10)         // None(安全访问,不抛异常)

注意s[i] 返回的是 Byte(UTF-8 编码字节),对于多字节字符(如中文),单个索引不能获取完整字符。

14.2 切片

let s = "Hello World"
let sub = s[0..5]   // "Hello"
let sub2 = s[6..11] // "World"

注意:切片范围基于字节索引,确保不要在多字节字符中间切断。


15. clone

func clone(): String
  • 返回字符串的一份拷贝(由于 String 是不可变类型,通常不需要手动克隆)

16. 常见用法总结

// 1. 判断空字符串
if (s.isEmpty()) { ... }

// 2. 安全搜索
if (let Some(idx) <- s.indexOf("key")) {
    println("Found at ${idx}")
}

// 3. 分割与重组
let parts = "a:b:c".split(":")
let joined = String.join(parts, delimiter: "-") // "a-b-c"

// 4. 裁剪用户输入
let input = "  user@example.com  ".trimAscii()

// 5. 路径处理
let filename = "path/to/file.cj"
if (filename.endsWith(".cj")) {
    let name = filename.removeSuffix(".cj")
}

// 6. 按行处理文本
for (line in text.lines()) {
    if (!line.isEmpty()) {
        processLine(line)
    }
}

// 7. 字符串重复
let separator = "=" * 40  // "========================================"

// 8. 大小写不敏感比较
if (cmd.equalsIgnoreAsciiCase("quit")) {
    exit(0)
}
Weekly Installs
3
First Seen
4 days ago
Installed on
opencode2
gemini-cli2
claude-code2
github-copilot2
codex2
kimi-cli2