Skip to content

复杂模式

这里展示了一些 OneBot Commander 的复杂模式匹配示例,帮助你掌握高级用法。

⚠️ 重要:空格敏感特性

在使用复杂模式时,请特别注意 OneBot Commander 对空格非常敏感

  • 模式中的每个空格都必须与输入文本中的空格完全匹配
  • 在复杂模式中,空格的处理变得更加重要
  • 建议在开发时仔细检查空格的使用

空格敏感示例

typescript
// 复杂模式: "config <key:text> [value:text] [type:text={text:string}]"
const commander = new Commander('config <key:text> [value:text] [type:text={text:string}]');

// ✅ 正确 - 所有空格都匹配
const segments1 = [{ type: 'text', data: { text: 'config theme dark' } }];
const result1 = commander.match(segments1); // 匹配成功

// ❌ 错误 - 缺少空格
const segments2 = [{ type: 'text', data: { text: 'configtheme dark' } }];
const result2 = commander.match(segments2); // 匹配失败

// ❌ 错误 - 多余空格
const segments3 = [{ type: 'text', data: { text: 'config  theme dark' } }];
const result3 = commander.match(segments3); // 匹配失败

多参数组合

1. 混合必需和可选参数

typescript
import { Commander } from 'onebot-commander';

const commander = new Commander('config <key:text> [value:text] [type:text={text:string}]'); // 注意参数间的空格

commander.action((params) => {
  const { key, value, type } = params;
  
  if (!value) {
    // 获取配置
    return { action: 'get', key, type };
  } else {
    // 设置配置
    return { action: 'set', key, value, type };
  }
});

// 设置配置
const segments1 = [
  { type: 'text', data: { text: 'config theme dark' } } // 注意参数间的空格
];
const result1 = commander.match(segments1);
console.log(result1[0]); // { action: 'set', key: 'theme', value: 'dark', type: { text: 'string' } }

// 获取配置
const segments2 = [
  { type: 'text', data: { text: 'config theme' } } // 注意参数间的空格
];
const result2 = commander.match(segments2);
console.log(result2[0]); // { action: 'get', key: 'theme', type: { text: 'string' } }

// 指定类型
const segments3 = [
  { type: 'text', data: { text: 'config timeout 30 number' } } // 注意参数间的空格
];
const result3 = commander.match(segments3);
console.log(result3[0]); // { action: 'set', key: 'timeout', value: '30', type: 'number' }

2. 复杂的数据结构

typescript
const commander = new Commander('user <name:text> <age:number> [email:text] [tags:text]'); // 注意参数间的空格

commander.action((params) => {
  const { name, age, email, tags } = params;
  
  const user = {
    name,
    age,
    email: email || null,
    tags: tags ? tags.split(',').map(tag => tag.trim()) : []
  };
  
  return { user, timestamp: Date.now() };
});

const segments = [
  { type: 'text', data: { text: 'user Alice 25 alice@example.com admin,moderator' } } // 注意参数间的空格
];

const results = commander.match(segments);
console.log(results[0]);
// {
//   user: {
//     name: 'Alice',
//     age: 25,
//     email: 'alice@example.com',
//     tags: ['admin', 'moderator']
//   },
//   timestamp: 1234567890
// }

类型化字面量组合

1. 多类型字面量

typescript
const commander = new Commander('{face:1}{text:start}<command:text>[count:number={value:1}]');

commander.action((params) => {
  const { command, count } = params;
  console.log(`表情 + 文本 + 命令: ${command}, 次数: ${count.value}`);
  return { type: 'complex_command', command, count };
});

const segments = [
  { type: 'face', data: { id: 1 } },
  { type: 'text', data: { text: 'start ping' } },
  { type: 'text', data: { text: '5' } }
];

const results = commander.match(segments);
console.log(results[0]); // { command: 'ping', count: 5 }

2. 条件类型化字面量

typescript
class ConditionalCommander {
  private commanders = new Map();
  
  constructor() {
    this.setupCommanders();
  }
  
  setupCommanders() {
    // 表情 + 命令
    const faceCommander = new Commander('{face:1}<command:text>');
    faceCommander.action((params) => {
      return { type: 'face_command', command: params.command };
    });
    this.commanders.set('face', faceCommander);
    
    // 图片 + 命令
    const imageCommander = new Commander('{image:icon.png}<command:text>');
    imageCommander.action((params) => {
      return { type: 'image_command', command: params.command };
    });
    this.commanders.set('image', imageCommander);
    
    // 文本 + 命令
    const textCommander = new Commander('{text:cmd}<command:text>');
    textCommander.action((params) => {
      return { type: 'text_command', command: params.command };
    });
    this.commanders.set('text', textCommander);
  }
  
  match(segments) {
    for (const [type, commander] of this.commanders) {
      try {
        const results = commander.match(segments);
        if (results.length > 0) {
          return { type, result: results[0] };
        }
      } catch (error) {
        // 继续尝试下一个
      }
    }
    return null;
  }
}

const conditionalCommander = new ConditionalCommander();

// 测试不同的组合
const testCases = [
  [
    { type: 'face', data: { id: 1 } },
    { type: 'text', data: { text: 'ping' } }
  ],
  [
    { type: 'image', data: { file: 'icon.png' } },
    { type: 'text', data: { text: 'upload' } }
  ],
  [
    { type: 'text', data: { text: 'cmd echo' } }
  ]
];

testCases.forEach((segments, index) => {
  const result = conditionalCommander.match(segments);
  console.log(`测试 ${index + 1}:`, result);
});

剩余参数高级用法

1. 智能剩余参数处理

typescript
const commander = new Commander('process [...items]');

commander.action((params) => {
  const { items = [] } = params;
  
  // 分析剩余参数
  const analysis = {
    total: items.length,
    types: {},
    textItems: [],
    numericItems: [],
    otherItems: []
  };
  
  for (const item of items) {
    // 统计类型
    analysis.types[item.type] = (analysis.types[item.type] || 0) + 1;
    
    // 分类处理
    if (item.type === 'text') {
      const text = item.data.text;
      analysis.textItems.push(text);
      
      // 检查是否为数字
      if (!isNaN(text)) {
        analysis.numericItems.push(Number(text));
      }
    } else {
      analysis.otherItems.push(item);
    }
  }
  
  return {
    action: 'process',
    analysis,
    summary: `处理了 ${analysis.total} 个项目,包含 ${Object.keys(analysis.types).length} 种类型`
  };
});

const segments = [
  { type: 'text', data: { text: 'process' } },
  { type: 'text', data: { text: 'hello' } },
  { type: 'text', data: { text: '123' } },
  { type: 'face', data: { id: 1 } },
  { type: 'image', data: { file: 'photo.jpg' } }
];

const results = commander.match(segments);
console.log(results[0]);
// {
//   action: 'process',
//   analysis: {
//     total: 4,
//     types: { text: 2, face: 1, image: 1 },
//     textItems: ['hello', '123'],
//     numericItems: [123],
//     otherItems: [{ type: 'face', data: { id: 1 } }, { type: 'image', data: { file: 'photo.jpg' } }]
//   },
//   summary: '处理了 4 个项目,包含 3 种类型'
// }

2. 分组剩余参数

typescript
const commander = new Commander('group [...items]');

commander.action((params) => {
  const { items = [] } = params;
  
  // 按类型分组
  const groups = {};
  
  for (const item of items) {
    if (!groups[item.type]) {
      groups[item.type] = [];
    }
    groups[item.type].push(item);
  }
  
  // 生成分组统计
  const stats = Object.entries(groups).map(([type, items]) => ({
    type,
    count: items.length,
    items
  }));
  
  return {
    action: 'group',
    groups,
    stats,
    totalGroups: Object.keys(groups).length,
    totalItems: items.length
  };
});

const segments = [
  { type: 'text', data: { text: 'group' } },
  { type: 'text', data: { text: 'item1' } },
  { type: 'text', data: { text: 'item2' } },
  { type: 'face', data: { id: 1 } },
  { type: 'face', data: { id: 2 } },
  { type: 'image', data: { file: 'photo1.jpg' } }
];

const results = commander.match(segments);
console.log(results[0]);
// {
//   action: 'group',
//   groups: {
//     text: [{ type: 'text', data: { text: 'item1' } }, { type: 'text', data: { text: 'item2' } }],
//     face: [{ type: 'face', data: { id: 1 } }, { type: 'face', data: { id: 2 } }],
//     image: [{ type: 'image', data: { file: 'photo1.jpg' } }]
//   },
//   stats: [
//     { type: 'text', count: 2, items: [...] },
//     { type: 'face', count: 2, items: [...] },
//     { type: 'image', count: 1, items: [...] }
//   ],
//   totalGroups: 3,
//   totalItems: 5
// }

嵌套模式

1. 子命令模式

typescript
class SubCommandManager {
  private commanders = new Map();
  
  constructor() {
    this.setupSubCommands();
  }
  
  setupSubCommands() {
    // git 命令
    const gitCommander = new Commander('git <subcommand:text> [...args]');
    gitCommander.action((params) => {
      const { subcommand, args = [] } = params;
      
      switch (subcommand) {
        case 'clone':
          return this.handleGitClone(args);
        case 'push':
          return this.handleGitPush(args);
        case 'pull':
          return this.handleGitPull(args);
        default:
          return { error: `未知的 git 子命令: ${subcommand}` };
      }
    });
    this.commanders.set('git', gitCommander);
    
    // docker 命令
    const dockerCommander = new Commander('docker <subcommand:text> [...args]');
    dockerCommander.action((params) => {
      const { subcommand, args = [] } = params;
      
      switch (subcommand) {
        case 'run':
          return this.handleDockerRun(args);
        case 'build':
          return this.handleDockerBuild(args);
        case 'stop':
          return this.handleDockerStop(args);
        default:
          return { error: `未知的 docker 子命令: ${subcommand}` };
      }
    });
    this.commanders.set('docker', dockerCommander);
  }
  
  handleGitClone(args) {
    const [repo, ...options] = args;
    return {
      command: 'git',
      subcommand: 'clone',
      repository: repo,
      options: options
    };
  }
  
  handleGitPush(args) {
    const [remote, branch] = args;
    return {
      command: 'git',
      subcommand: 'push',
      remote: remote || 'origin',
      branch: branch || 'main'
    };
  }
  
  handleGitPull(args) {
    const [remote, branch] = args;
    return {
      command: 'git',
      subcommand: 'pull',
      remote: remote || 'origin',
      branch: branch || 'main'
    };
  }
  
  handleDockerRun(args) {
    const [image, ...options] = args;
    return {
      command: 'docker',
      subcommand: 'run',
      image,
      options
    };
  }
  
  handleDockerBuild(args) {
    const [context, ...options] = args;
    return {
      command: 'docker',
      subcommand: 'build',
      context: context || '.',
      options
    };
  }
  
  handleDockerStop(args) {
    const [container] = args;
    return {
      command: 'docker',
      subcommand: 'stop',
      container
    };
  }
  
  match(segments) {
    for (const [command, commander] of this.commanders) {
      try {
        const results = commander.match(segments);
        if (results.length > 0) {
          return results[0];
        }
      } catch (error) {
        // 继续尝试下一个
      }
    }
    return null;
  }
}

const manager = new SubCommandManager();

// 测试不同的子命令
const testCommands = [
  { type: 'text', data: { text: 'git clone https://github.com/user/repo.git' } },
  { type: 'text', data: { text: 'git push origin main' } },
  { type: 'text', data: { text: 'docker run nginx' } },
  { type: 'text', data: { text: 'docker build .' } }
];

testCommands.forEach((segments, index) => {
  const result = manager.match([segments]);
  console.log(`命令 ${index + 1}:`, result);
});

2. 层级命令结构

typescript
class HierarchicalCommandManager {
  private commanders = new Map();
  
  constructor() {
    this.setupHierarchy();
  }
  
  setupHierarchy() {
    // 系统命令
    const systemCommander = new Commander('system <action:text> [target:text]');
    systemCommander.action((params) => {
      const { action, target } = params;
      return { level: 'system', action, target };
    });
    this.commanders.set('system', systemCommander);
    
    // 应用命令
    const appCommander = new Commander('app <name:text> <action:text> [...args]');
    appCommander.action((params) => {
      const { name, action, args = [] } = params;
      return { level: 'app', name, action, args };
    });
    this.commanders.set('app', appCommander);
    
    // 用户命令
    const userCommander = new Commander('user <id:text> <action:text> [...args]');
    userCommander.action((params) => {
      const { id, action, args = [] } = params;
      return { level: 'user', id, action, args };
    });
    this.commanders.set('user', userCommander);
  }
  
  match(segments) {
    for (const [level, commander] of this.commanders) {
      try {
        const results = commander.match(segments);
        if (results.length > 0) {
          return { level, ...results[0] };
        }
      } catch (error) {
        // 继续尝试下一个
      }
    }
    return null;
  }
}

const hierarchicalManager = new HierarchicalCommandManager();

// 测试不同层级的命令
const testHierarchy = [
  { type: 'text', data: { text: 'system restart server' } },
  { type: 'text', data: { text: 'app webapp start --port 3000' } },
  { type: 'text', data: { text: 'user 12345 login --remember' } }
];

testHierarchy.forEach((segments, index) => {
  const result = hierarchicalManager.match([segments]);
  console.log(`层级命令 ${index + 1}:`, result);
});

动态模式生成

1. 基于配置的模式

typescript
class DynamicPatternGenerator {
  constructor(config) {
    this.config = config;
  }
  
  generatePattern(command) {
    const { parameters, options } = this.config[command] || {};
    
    if (!parameters) {
      return command;
    }
    
    let pattern = command;
    
    // 添加必需参数
    for (const param of parameters.required || []) {
      pattern += ` <${param.name}:${param.type}>`;
    }
    
    // 添加可选参数
    for (const param of parameters.optional || []) {
      const defaultValue = param.default ? `=${param.default}` : '';
      pattern += ` [${param.name}:${param.type}${defaultValue}]`;
    }
    
    // 添加剩余参数
    if (parameters.rest) {
      pattern += ` [...${parameters.rest.name}]`;
    }
    
    return pattern;
  }
  
  createCommander(command) {
    const pattern = this.generatePattern(command);
    return new Commander(pattern);
  }
}

// 配置示例
const commandConfig = {
  'user': {
    parameters: {
      required: [
        { name: 'name', type: 'text' },
        { name: 'age', type: 'number' }
      ],
      optional: [
        { name: 'email', type: 'text' },
        { name: 'role', type: 'text', default: 'user' }
      ]
    }
  },
  'file': {
    parameters: {
      required: [
        { name: 'action', type: 'text' },
        { name: 'path', type: 'text' }
      ],
      optional: [
        { name: 'mode', type: 'text', default: 'read' }
      ],
      rest: { name: 'options' }
    }
  }
};

const generator = new DynamicPatternGenerator(commandConfig);

// 生成命令解析器
const userCommander = generator.createCommander('user');
const fileCommander = generator.createCommander('file');

console.log('生成的模式:');
console.log('user:', generator.generatePattern('user'));
// 输出: user <name:text> <age:number> [email:text] [role:text=user]

console.log('file:', generator.generatePattern('file'));
// 输出: file <action:text> <path:text> [mode:text=read] [...options]

// 使用生成的解析器
userCommander.action((params) => {
  console.log('用户参数:', params);
  return { type: 'user', ...params };
});

const segments = [
  { type: 'text', data: { text: 'user Alice 25 alice@example.com' } }
];

const results = userCommander.match(segments);
console.log('匹配结果:', results[0]);

2. 模板模式

typescript
class TemplatePatternManager {
  constructor() {
    this.templates = new Map();
    this.setupTemplates();
  }
  
  setupTemplates() {
    // CRUD 模板
    this.templates.set('crud', {
      pattern: '{entity} <action:text> [id:text] [...data]',
      description: '通用的 CRUD 操作模板'
    });
    
    // 查询模板
    this.templates.set('query', {
      pattern: 'query <target:text> [filter:text] [limit:number=10] [offset:number=0]',
      description: '通用查询模板'
    });
    
    // 配置模板
    this.templates.set('config', {
      pattern: 'config <key:text> [value:text] [type:text=string]',
      description: '配置管理模板'
    });
  }
  
  createFromTemplate(templateName, entity) {
    const template = this.templates.get(templateName);
    if (!template) {
      throw new Error(`未知模板: ${templateName}`);
    }
    
    let pattern = template.pattern;
    
    // 替换实体占位符
    if (entity) {
      pattern = pattern.replace('{entity}', entity);
    }
    
    return new Commander(pattern);
  }
  
  getAvailableTemplates() {
    return Array.from(this.templates.entries()).map(([name, template]) => ({
      name,
      pattern: template.pattern,
      description: template.description
    }));
  }
}

const templateManager = new TemplatePatternManager();

// 使用 CRUD 模板创建用户管理命令
const userCrudCommander = templateManager.createFromTemplate('crud', 'user');
userCrudCommander.action((params) => {
  const { action, id, data = [] } = params;
  return { entity: 'user', action, id, data };
});

// 使用查询模板创建搜索命令
const searchCommander = templateManager.createFromTemplate('query', null);
searchCommander.action((params) => {
  const { target, filter, limit, offset } = params;
  return { action: 'query', target, filter, limit, offset };
});

// 测试模板生成的命令
const testTemplates = [
  { type: 'text', data: { text: 'user create 123 name:Alice age:25' } },
  { type: 'text', data: { text: 'query users active 20 0' } }
];

testTemplates.forEach((segments, index) => {
  const result = userCrudCommander.match([segments]);
  console.log(`模板命令 ${index + 1}:`, result);
});

// 显示可用模板
console.log('可用模板:', templateManager.getAvailableTemplates());

下一步


💡 提示

复杂模式展示了 OneBot Commander 的强大功能,合理使用这些高级特性可以构建更加灵活和强大的命令解析系统。

Released under the MIT License.