Appendix A. Implementation Hints (实现提示)
扩展的规范性章节为了描述清晰,为每个操作符描述了单独的扩展过程。在实际实现中,我们期望表达式使用通用算法从左到右处理,该算法对于每个操作符只有很小的过程变化。这个非规范性附录描述了一种这样的算法。
初始化一个空的结果字符串及其非错误状态。
扫描模板并将字面量复制到结果字符串(如第3.1节所述),直到遇到由 "{" 表示的表达式、由除 "{" 之外的非字面量字符的存在表示的错误,或模板结束。当它结束时,返回结果字符串及其当前的错误或非错误状态。
- 如果找到表达式,扫描模板到下一个
"}"并提取花括号之间的字符。 - 如果模板在
"}"之前结束,则将"{"和提取的字符附加到结果字符串,并返回错误状态,指示表达式格式错误。
检查提取的表达式的第一个字符以查找操作符。
- 如果表达式结束(即为
"{}"),找到未知或未实现的操作符,或字符不在varchar集中(第2.3节),则将"{"、提取的表达式和"}"附加到结果字符串,记住结果处于错误状态,然后返回扫描模板的其余部分。 - 如果找到已知且已实现的操作符,存储操作符并跳到下一个字符以开始varspec列表。
- 否则,将操作符存储为NUL(简单字符串扩展)。
使用以下值表按表达式类型操作符确定处理行为。"first"条目是在表达式的任何变量已定义时首先附加到结果的字符串。"sep"条目是在任何第二个(或后续)已定义的变量扩展之前附加到结果的分隔符。"named"条目是一个布尔值,表示当没有给出爆炸修饰符时,扩展是否包含变量或键名。"ifemp"条目是在其对应值为空时附加到名称的字符串。"allow"条目指示在值扩展中允许未编码的字符:(U) 表示未在非保留集中的任何字符将被编码;(U+R) 表示未在 (unreserved / reserved / pct-encoding) 并集中的任何字符将被编码;对于这两种情况,每个不允许的字符首先被编码为其在UTF-8中的八位字节序列,然后每个这样的八位字节被编码为百分号编码三元组。
┌──────────────────────────────────────────────────────────────┐
│ NUL + . / ; ? & #│
├──────────────────────────────────────────────────────────────┤
│ first │ "" "" "." "/" ";" "?" "&" "#"│
│ sep │ "," "," "." "/" ";" "&" "&" "," │
│ named │ false false false false true true true false│
│ ifemp │ "" "" "" "" "" "=" "=" "" │
│ allow │ U U+R U U U U U U+R │
└──────────────────────────────────────────────────────────────┘
考虑到上表,按如下方式处理变量列表:
对于每个varspec,通过扫描变量列表直到找到不在varname集中的字符或达到表达式的结尾,从表达式中提取变量名和可选修饰符。
- 如果是表达式的结尾且varname为空,则返回扫描模板的其余部分。
- 如果不是表达式的结尾且找到的最后一个字符指示修饰符(""或":"),记住该修饰符。如果是爆炸(""),扫描下一个字符。如果是前缀(":"),继续扫描下一个一到四个字符以获取表示为十进制整数的max-length,然后,如果仍然不是表达式的结尾,扫描下一个字符。
- 如果不是表达式的结尾且找到的最后一个字符不是逗号(","),将"、存储的操作符(如果有)、扫描的varname和修饰符、剩余的表达式和"附加到结果字符串,记住结果处于错误状态,然后返回扫描模板的其余部分。
查找扫描的变量名的值,然后
- 如果varname未知或对应于具有未定义值的变量(第2.3节),则跳到下一个varspec。
- 如果这是此表达式的第一个已定义变量,则将此表达式类型的first字符串附加到结果字符串,并记住已完成。否则,将sep字符串附加到结果字符串。
- 如果此变量的值是字符串,则
- 如果named为true,则使用与字面量相同的编码过程将varname附加到结果字符串,并且
- 如果值为空,将ifemp字符串附加到结果字符串并跳到下一个varspec;
- 否则,将"="附加到结果字符串。
- 如果存在前缀修饰符且前缀长度小于以Unicode字符数表示的值字符串长度,则将该数量的字符从值字符串的开头附加到结果字符串,在不在allow集中的任何字符之后进行百分号编码,同时注意不要拆分表示单个Unicode代码点的多八位字节或百分号编码三元组字符;
- 否则,在不在allow集中的任何字符之后进行百分号编码后,将值附加到结果字符串。
- 如果named为true,则使用与字面量相同的编码过程将varname附加到结果字符串,并且
- 否则,如果没有给出爆炸修饰符,则
- 如果named为true,则使用与字面量相同的编码过程将varname附加到结果字符串,并且
- 如果值为空,将ifemp字符串附加到结果字符串并跳到下一个varspec;
- 否则,将"="附加到结果字符串;并且
- 如果此变量的值是列表,则在不在allow集中的任何字符之后进行百分号编码后,将每个已定义的列表成员附加到结果字符串,在每个已定义的列表成员之间将逗号(",")附加到结果;
- 如果此变量的值是关联数组或任何其他形式的配对(name, value)结构,则在不在allow集中的任何字符之后进行百分号编码后,将每个具有已定义值的对作为"name,value"附加到结果字符串,在每个已定义的对之间将逗号(",")附加到结果。
- 如果named为true,则使用与字面量相同的编码过程将varname附加到结果字符串,并且
- 否则,如果给出爆炸修饰符,则
- 如果named为true,则对于每个已定义的列表成员或具有已定义值的数组(name, value)对,执行:
- 如果这不是第一个已定义的成员/值,将sep字符串附加到结果字符串;
- 如果这是列表,使用与字面量相同的编码过程将varname附加到结果字符串;
- 如果这是对,使用与字面量相同的编码过程将name附加到结果字符串;
- 如果成员/值为空,将ifemp字符串附加到结果字符串;否则,在不在allow集中的任何成员/值字符之后进行百分号编码后,将"="和成员/值附加到结果字符串。
- 否则,如果named为false,则
- 如果这是列表,在不在allow集中的任何字符之后进行百分号编码后,将每个已定义的列表成员附加到结果字符串,在每个已定义的列表成员之间将sep字符串附加到结果。
- 如果这是(name, value)对的数组,在不在allow集中的任何字符之后进行百分号编码后,将每个具有已定义值的对作为"name=value"附加到结果字符串,在每个已定义的对之间将sep字符串附加到结果。
- 如果named为true,则对于每个已定义的列表成员或具有已定义值的数组(name, value)对,执行:
当此表达式的变量列表用尽时,返回扫描模板的其余部分。