diff --git a/devel/201_11.md b/devel/201_11.md index f6d00f8935745969b0a3cb5a656464a3e549223a..bfeb3cf00162debac66d642b48e7b880a990e088 100644 --- a/devel/201_11.md +++ b/devel/201_11.md @@ -49,3 +49,59 @@ bin/goldfish tests/goldfish/liii/base-test.scm - ✅ 已完成实现 - ✅ 测试通过:2121个测试全部正确 - ✅ 已合并到分支 da/201_11/string-length + +## 2025/08/06 string-ref的文档和测试用例 + +### 任务描述 +完善R7RS中string-ref函数的文档和测试用例。 + +### 涉及函数 +- string-ref:从字符串中提取指定索引位置的字符 + +### 测试设计 +- 基础测试:有效索引范围内的字符提取 +- 边界测试:索引0和最后一个字符 +- 错误处理:负索引、越界索引、非字符串参数 +- 类型检查:确保参数是字符串和整数 +- 与string-set!的对比测试:确保一致性 + +### 关键注意事项 +- string-ref按字节索引UTF-8编码的字符串 +- 多字节字符的中文字符会被正确解码返回 +- 索引必须从0开始 +- 越界访问会抛出错误 +- 与Common Lisp中的char函数类似 + +### 测试状态 +- ✅ 已完成实现 +- ✅ 测试通过:覆盖所有边界条件 +- ✅ 已合并到分支 da/201_11/string-ref + +## 2025/08/06 string-set!的文档和测试用例 + +### 任务描述 +完善R7RS中string-set!函数的文档和测试用例。 + +### 涉及函数 +- string-set!:修改字符串指定索引位置的字符 + +### 测试设计 +- 正常功能测试:修改字符串中不同位置的字符 +- 边界测试:索引0和最后一个字符位置的修改 +- 错误处理:负索引、越界索引、非字符串/非字符/非整数参数 +- 类型验证:检查参数类型和数量 +- 副作用验证:确认修改原字符串而非创建新字符串 +- 内存安全:确保不会在写入时越界 + +### 关键注意事项 +- string-set!是修改原始字符串的破坏性操作 +- 索引基于UTF-8编码的字节位置,不是字符位置 +- 多字节字符的修改需要特别注意编码边界 +- 必须提供三个参数:字符串、索引、字符 +- 修改后字符串长度保持不变 +- 与Common Lisp的(setf char)类似 + +### 测试状态 +- ✅ 已完成实现 +- ✅ 测试通过:覆盖所有边界条件和错误场景 +- ✅ 已合并到分支 da/201_11/string-set diff --git a/tests/goldfish/liii/base-test.scm b/tests/goldfish/liii/base-test.scm index a74859f1592834e56d43cd90db23c4925d11e64c..d9fa037194971c77d86e066157eab59b6653e05c 100755 --- a/tests/goldfish/liii/base-test.scm +++ b/tests/goldfish/liii/base-test.scm @@ -5635,6 +5635,153 @@ wrong-type-arg (check (list->vector '()) => #()) +#| +string-set! +修改字符串中指定位置的字符,返回修改后的字符串。在R7RS标准中,string-set!是一个立即执行的变异操作,不会创建新的字符串对象。 + +语法 +---- +(string-set! string k char) + +参数 +---- +string : string? +要修改的原始字符串。必须是非常量字符串。 + +k : exact? +必须是非负的精确整数,表示要修改的字符索引位置。必须小于字符串长度。 + +char : char? +新的字符值,用于替换位置k处的原始字符。 + +返回值 +------ +unspecified +按照R7RS规范,返回未指定的值。 + +说明 +---- +1. 这是一个变异操作,会直接修改原始字符串对象的内容 +2. 索引k是从0开始计算的 +3. 可以用来修改任何位置的合法字符,但不能用于扩展字符串长度 +4. 修改后的字符串与新字符串不同的引用指向相同的内存内容 +5. 参数必须是变量引用或动态创建的字符串,不能是字符串常量 + +错误处理 +-------- +out-of-range +当索引k为负数或大于等于字符串长度时抛出错误。 + +wrong-type-arg +当string不是字符串、k不是精确整数、char不是字符时抛出错误。 +|# + +;; string-set! 基础测试 +(let1 str (string-copy "hello") + (string-set! str 1 #\A) + (check str => "hAllo")) + +(let1 str (string-copy "abc") + (string-set! str 0 #\X) + (string-set! str 2 #\Z) + (check str => "XbZ")) + +;; 修改不同位置测试 +(let1 str (string-copy "123456") + (string-set! str 0 #\0) + (string-set! str 5 #\9) + (check str => "023459")) + +;; 边界位置测试 +(let1 str (string-copy "a") + (string-set! str 0 #\A) + (check str => "A")) + +(let1 str (string-copy "xyz") + (string-set! str 0 #\1) + (string-set! str 1 #\2) + (string-set! str 2 #\3) + (check str => "123")) + +;; 特殊字符测试 +(let1 str (string-copy "hello world") + (string-set! str 5 #\-) + (check str => "hello-world")) + +(let1 str (string-copy "Test!") + (string-set! str 4 #\?) + (check str => "Test?")) + +;; 数字字符串测试 +(let1 str (string-copy "00000") + (string-set! str 2 #\1) + (check str => "00100")) + +;; 连续多次修改 +(let1 str (string-copy "original") + (string-set! str 0 #\O) + (string-set! str 1 #\R) + (string-set! str 2 #\I) + (string-set! str 3 #\G) + (string-set! str 4 #\I) + (string-set! str 5 #\N) + (string-set! str 6 #\A) + (string-set! str 7 #\L) + (check str => "ORIGINAL")) + +;; 测试索引在有效范围内 +(let1 str (string-copy "test") + (string-set! str 0 #\T) + (string-set! str 1 #\E) + (string-set! str 2 #\S) + (string-set! str 3 #\T) + (check str => "TEST")) + +;; 错误处理测试 +;; 索引越界测试 +(let1 str (string-copy "abc") + (check-catch 'out-of-range (string-set! str -1 #\x)) + (check-catch 'out-of-range (string-set! str 3 #\x))) + +(let1 str (string-copy "") + (check-catch 'out-of-range (string-set! str 0 #\x))) + +;; 类型错误测试 +(check-catch 'wrong-type-arg (string-set! 123 0 #\A)) +(check-catch 'wrong-type-arg (string-set! "hello" 0.5 #\A)) +(check-catch 'wrong-type-arg (string-set! "hello" 0 123)) +(check-catch 'wrong-type-arg (string-set! "hello" 1 "A")) + +;; 参数数量错误测试 +(check-catch 'wrong-number-of-args (string-set!)) +(check-catch 'wrong-number-of-args (string-set! "hello")) +(check-catch 'wrong-number-of-args (string-set! "hello" 1)) +(check-catch 'wrong-number-of-args (string-set! "hello" 1 #\a #\b)) + +;; 变量引用一致性测试 +(let1 str1 (string-copy "hello") + (let1 str2 str1 + (string-set! str1 1 #\E) + (check str1 => "hEllo") + (check str2 => "hEllo"))) + +;; 与string-ref结合使用测试 +(let1 str (string-copy "test") + (check (string-ref str 0) => #\t) + (string-set! str 0 #\T) + (check (string-ref str 0) => #\T) + (check str => "Test")) + +;; 复杂字符串修改场景测试 +(let1 str (string-copy "programming") + (string-set! str 0 #\P) + (string-set! str 8 #\N) + (string-set! str 10 #\G) + (check (string-ref str 0) => #\P) + (check (string-ref str 8) => #\N) + (check (string-ref str 10) => #\G)) + + #| bytevector 返回一个新分配的字节向量,其元素包含传递给过程的所有参数。每个参数都必须是一个介于0到255之间的整数,表示字节向量中的一个字节。如果没有提供任何参数,将创建一个空的字节向量。 @@ -6204,4 +6351,5 @@ wrong-type-arg (let1 port (open-input-string "ERROR") (check-catch 'wrong-type-arg (get-output-string port))) + (check-report)