Skip to content

模式语法

OneBot Commander 使用简洁而强大的模式语法来描述消息段结构。本章将详细介绍所有支持的语法元素。

⚠️ 重要:空格敏感特性

OneBot Commander 对空格非常敏感,这是一个重要的特性:

  • 模式中的空格必须与输入文本中的空格完全匹配
  • 缺少空格或多余空格都会导致匹配失败
  • 这个特性确保了命令的精确匹配

空格敏感示例

typescript
// 模式: "ping [count:number={value:1}]"
const commander = new Commander('ping [count:number={value:1}]');

// ✅ 匹配成功 - 有空格
commander.match([{ type: 'text', data: { text: 'ping ' } }]);

// ❌ 匹配失败 - 没有空格
commander.match([{ type: 'text', data: { text: 'ping' } }]);

// ❌ 匹配失败 - 多余空格
commander.match([{ type: 'text', data: { text: 'ping  ' } }]);

空格处理最佳实践

typescript
// 1. 明确指定空格
const commander1 = new Commander('hello <name:text>'); // 注意 "hello " 后面的空格

// 2. 使用可选参数时注意空格
const commander2 = new Commander('ping [count:number={value:1}]'); // "ping " 后面的空格

// 3. 多参数时的空格处理
const commander3 = new Commander('echo <message:text> <count:number>'); // 参数间的空格

基本语法元素

1. 文本字面量

纯文本,直接匹配(注意空格):

typescript
const commander = new Commander('hello ');
// 匹配: "hello " (注意末尾的空格)
// 不匹配: "hello" (没有空格)

2. 必需参数

使用尖括号 <> 表示必需参数:

typescript
const commander = new Commander('hello <name:text>');
// 匹配: "hello Alice" -> { name: 'Alice' }

语法:<参数名:类型>

3. 可选参数

使用方括号 [] 表示可选参数:

typescript
const commander = new Commander('ping [message:text]');
// 匹配: "ping" -> {}
// 匹配: "ping hello" -> { message: 'hello' }

语法:[参数名:类型]

4. 类型化字面量

使用花括号 {} 表示类型化字面量:

typescript
const commander = new Commander('{text:test}<arg:text>');
// 匹配: "test123" -> { arg: '123' }

语法:{类型:值}

5. 剩余参数

使用 ... 表示剩余参数:

typescript
const commander = new Commander('test[...rest]');
// 匹配: "test a b c" -> { rest: ['a', 'b', 'c'] }

语法:[...参数名][...参数名:类型]

支持的数据类型

基础类型

类型描述示例
text文本类型"hello world"
number数字类型123, 3.14
boolean布尔类型true, false

OneBot 消息段类型

类型描述数据字段
face表情data.id
image图片data.filedata.url
voice语音data.file
video视频data.file
file文件data.file
at@用户data.user_id
reply回复data.id
forward转发data.id
jsonJSONdata.data
xmlXMLdata.data
card卡片data.data

复杂模式示例

混合参数模式

typescript
// 必需参数 + 可选参数
const commander1 = new Commander('test<arg1:text>[arg2:face]');

// 类型化字面量 + 参数
const commander2 = new Commander('{text:start}<arg:text>[opt:face]');

// 多个必需参数
const commander3 = new Commander('echo <message:text> <count:number>');

剩余参数模式

typescript
// 通用剩余参数
const commander1 = new Commander('test[...rest]');

// 类型化剩余参数
const commander2 = new Commander('test[...faces:face]');

// 混合剩余参数
const commander3 = new Commander('test<first:text>[...rest]');

默认值支持

typescript
// 文本默认值
const commander1 = new Commander('foo[msg:text={text:hello}]');

// 表情默认值
const commander2 = new Commander('foo[emoji:face={id:1}]');

// 数字默认值
const commander3 = new Commander('foo[count:number={value:10}]');

高级语法特性

1. 嵌套参数

typescript
// 复杂对象参数
const commander = new Commander('config <settings:json>');

// 匹配 JSON 数据
const segments = [
  { type: 'text', data: { text: 'config' } },
  { type: 'json', data: { data: '{"theme":"dark"}' } }
];

2. 条件匹配

typescript
// 使用类型化字面量进行条件匹配
const commander = new Commander('{face:1}<command:text>');

// 只有表情 ID 为 1 时才会匹配
const segments = [
  { type: 'face', data: { id: 1 } },
  { type: 'text', data: { text: 'hello' } }
];

3. 多字段匹配

typescript
// 图片支持 file 和 url 字段
const commander = new Commander('{image:avatar.png}<name:text>');

// 匹配 data.file 或 data.url
const segments = [
  { type: 'image', data: { file: 'avatar.png' } },
  { type: 'text', data: { text: 'Alice' } }
];

自定义字段映射

默认映射

typescript
const DEFAULT_MAPPING = {
  text: 'text',
  face: 'id',
  image: ['file', 'url'],
  at: 'user_id',
  // ... 其他类型
};

自定义映射

typescript
const customMapping = {
  image: 'src',  // 只匹配 data.src
  face: 'face_id',  // 匹配 data.face_id
  text: 'content'  // 匹配 data.content
};

const commander = new Commander('{image:avatar.png}<name:text>', customMapping);

模式解析规则

1. 优先级规则

  1. 类型化字面量优先级最高
  2. 必需参数次之
  3. 可选参数优先级最低
  4. 剩余参数最后匹配

2. 匹配顺序

typescript
// 模式: "test<arg1:text>[arg2:face]"
// 匹配顺序:
// 1. 匹配字面量 "test"
// 2. 匹配必需参数 arg1
// 3. 尝试匹配可选参数 arg2
// 4. 返回匹配结果

3. 失败处理

typescript
// 匹配失败时返回空数组
const result = commander.match(segments);
if (result.length === 0) {
  console.log('匹配失败');
}

常见模式示例

机器人命令

typescript
// 基础命令
const echo = new Commander('echo <message:text>');
const ping = new Commander('ping [count:number]');
const help = new Commander('help [command:text]');

// 复杂命令
const config = new Commander('config <key:text> <value:text>');
const search = new Commander('search <query:text> [...options:text]');

消息处理

typescript
// 表情反应
const react = new Commander('{face:1}<message:text>');

// 图片处理
const image = new Commander('{image:avatar.png}<caption:text>');

// @用户
const mention = new Commander('{at:123456}<message:text>');

系统命令

typescript
// 系统信息
const info = new Commander('info [detail:text]');

// 状态查询
const status = new Commander('status [service:text]');

// 日志查看
const logs = new Commander('logs [level:text] [count:number]');

最佳实践

1. 模式设计

typescript
// ✅ 好的模式设计
const good = new Commander('command <required:text> [optional:face]');

// ❌ 避免过于复杂的模式
const bad = new Commander('cmd<arg1:text>[arg2:face][arg3:image][arg4:at]');

2. 参数命名

typescript
// ✅ 使用描述性名称
const commander = new Commander('user <username:text> <action:text>');

// ❌ 避免模糊名称
const commander = new Commander('user <a:text> <b:text>');

3. 类型选择

typescript
// ✅ 选择合适的类型
const commander = new Commander('count <number:number>');

// ❌ 避免类型不匹配
const commander = new Commander('count <number:text>');

4. 错误处理

typescript
try {
  const commander = new Commander(pattern);
} catch (error) {
  if (error instanceof PatternParseError) {
    console.error('模式语法错误:', error.message);
  }
}

调试技巧

1. 查看解析结果

typescript
const commander = new Commander('hello <name:text>');
const tokens = commander.getTokens();
console.log('解析的令牌:', tokens);

2. 测试模式

typescript
function testPattern(pattern, segments) {
  try {
    const commander = new Commander(pattern);
    const result = commander.match(segments);
    console.log('匹配结果:', result);
    return result.length > 0;
  } catch (error) {
    console.error('模式错误:', error.message);
    return false;
  }
}

下一步


💡 提示

模式语法是 OneBot Commander 的核心,掌握好语法规则可以创建出强大而灵活的消息处理逻辑。

Released under the MIT License.