使用指南
🌟 新特性速览
单个文本段多参数提取
现在支持从单个连续文本段中自动提取多个参数:
typescript
const matcher = new SegmentMatcher('cmd [a:number] [b:number] [c:number]');
// 单个文本段,自动提取
matcher.match([{ type: 'text', data: { text: 'cmd 10 20 30' } }]);
// 结果: { a: 10, b: 20, c: 30 }word 类型 - 提取单词
新增 word 类型,用于提取非空格字符序列:
typescript
const matcher = new SegmentMatcher('config [key:word] [value:word]');
matcher.match([{ type: 'text', data: { text: 'config database mysql' } }]);
// 结果: { key: 'database', value: 'mysql' }对比 text 类型:
word- 匹配单个单词,不会贪婪匹配text- 匹配所有剩余文本(贪婪)
引号支持 - 包含空格的文本
使用引号(单引号或双引号)来提取包含空格的多个 text 参数:
typescript
const matcher = new SegmentMatcher('post [title:text] [author:word] [tags:text]');
// 使用双引号
matcher.match([{
type: 'text',
data: { text: 'post "Getting Started" alice "tutorial beginner"' }
}]);
// 结果: {
// title: 'Getting Started',
// author: 'alice',
// tags: 'tutorial beginner'
// }
// 嵌套不同类型引号
matcher.match([{
type: 'text',
data: { text: `post "It's great" bob 'He said "hello"'` }
}]);
// 结果: {
// title: "It's great",
// author: 'bob',
// tags: 'He said "hello"'
// }引号规则:
- 双引号内可以使用单引号
- 单引号内可以使用双引号
- 相同类型的引号不能嵌套
智能空格处理
参数间的单个空格自动处理(可选匹配):
typescript
const matcher = new SegmentMatcher('move [x:number] [y:number]');
// 以下输入都可以匹配
matcher.match([{ type: 'text', data: { text: 'move 10 20' } }]); // 有空格 ✅
matcher.match([{ type: 'text', data: { text: 'move 1020' } }]); // 紧贴也行 ✅
// 但多个空格视为字面量,必须精确匹配
const strict = new SegmentMatcher('move [x:number]'); // 两个空格
strict.match([{ type: 'text', data: { text: 'move 10' } }]); // ✅
strict.match([{ type: 'text', data: { text: 'move 10' } }]); // ❌基础概念
消息段
消息段是一个具有 type 和 data 字段的对象:
typescript
interface MessageSegment {
type: string;
data: Record<string, any>;
}常见的消息段类型:
text: 文本消息typescript{ type: 'text', data: { text: 'hello' } }at: @某人typescript{ type: 'at', data: { user_id: 123456 } }face: 表情typescript{ type: 'face', data: { id: 1 } }image: 图片typescript{ type: 'image', data: { file: 'image.jpg' } }
模式语法
字面量
直接匹配文本:
typescript
const matcher = new SegmentMatcher('hello');
// 匹配 { type: 'text', data: { text: 'hello' } }类型化字面量
匹配特定类型的消息段:
typescript
const matcher = new SegmentMatcher('{text:hello}{at:123456}');
// 匹配:
// [
// { type: 'text', data: { text: 'hello' } },
// { type: 'at', data: { user_id: 123456 } }
// ]参数
提取参数值:
typescript
const matcher = new SegmentMatcher('hello <name:text>');
// 从 'hello Alice' 中提取 name = 'Alice'可选参数
带默认值的可选参数:
typescript
const matcher = new SegmentMatcher('repeat [times:number=1]');
// 'repeat' → times = 1
// 'repeat 3' → times = 3剩余参数
收集剩余的消息段:
typescript
const matcher = new SegmentMatcher('images[...urls:image]');
// 收集所有图片消息段高级用法
自定义字段映射
单字段映射
typescript
const matcher = new SegmentMatcher('image <img:image>', {
image: 'url' // 使用 url 字段
});多字段优先级
typescript
const matcher = new SegmentMatcher('image <img:image>', {
image: ['url', 'file', 'src'] // 按顺序尝试
});特殊类型规则
数字类型
typescript
// 数字(整数或小数)
const matcher1 = new SegmentMatcher('<n:number>');
// 匹配: '123', '3.14'
// 整数
const matcher2 = new SegmentMatcher('<n:integer>');
// 匹配: '123'
// 小数
const matcher3 = new SegmentMatcher('<n:float>');
// 匹配: '3.14'布尔类型
typescript
const matcher = new SegmentMatcher('<enabled:boolean>');
// 匹配: 'true', 'false'空格处理
精确匹配
typescript
// 'hello ' 后有空格
const matcher = new SegmentMatcher('hello <name:text>');
// ✅ 匹配成功
matcher.match([{ type: 'text', data: { text: 'hello Alice' } }]);
// ❌ 匹配失败
matcher.match([{ type: 'text', data: { text: 'helloAlice' } }]);忽略空格
使用类型化字面量:
typescript
const matcher = new SegmentMatcher('{text:hello}<name:text>');
// 可以匹配 'hello Alice' 和 'helloAlice'错误处理
验证错误
typescript
try {
// 无效的模式
new SegmentMatcher(''); // 抛出 ValidationError
// 无效的参数
matcher.match(null); // 抛出 ValidationError
} catch (error) {
if (error instanceof ValidationError) {
console.error('验证错误:', error.message);
}
}匹配失败
typescript
const result = matcher.match(segments);
if (result === null) {
console.log('匹配失败');
} else {
console.log('匹配成功:', result);
}性能优化
缓存机制
类型检查缓存
typescript// 自动缓存类型检查结果 const matcher = new SegmentMatcher('pattern'); matcher.match(segments); // 首次检查 matcher.match(segments); // 使用缓存模式解析缓存
typescript// 相同的模式只解析一次 const m1 = new SegmentMatcher('pattern'); const m2 = new SegmentMatcher('pattern'); // 使用缓存
优化策略
重用实例
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('pattern'); for (const seg of segments) { matcher.match(seg); }使用字段映射
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('pattern', { image: 'url' // 只访问需要的字段 });避免不必要的类型检查
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('[...rest]'); // 不指定类型
最佳实践
模式设计
使用明确的类型
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('<count:integer>'); // ❌ 不好的做法 const matcher = new SegmentMatcher('<count:number>');合理使用可选参数
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('cmd [opt:text]'); // ❌ 不好的做法 const matcher = new SegmentMatcher('cmd<opt:text>');注意空格敏感性
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('cmd <arg:text>'); // 明确的空格 // ❌ 不好的做法 const matcher = new SegmentMatcher('cmd<arg:text>'); // 模糊的空格要求
错误处理
使用类型断言
typescript// ✅ 好的做法 if (result?.params.count != null) { const count = result.params.count as number; }提供默认值
typescript// ✅ 好的做法 const count = result?.params.count ?? 1;
性能考虑
缓存实例
typescript// ✅ 好的做法 const matchers = new Map<string, SegmentMatcher>(); function getMatcher(pattern: string) { if (!matchers.has(pattern)) { matchers.set(pattern, new SegmentMatcher(pattern)); } return matchers.get(pattern)!; }使用适当的类型
typescript// ✅ 好的做法 const matcher = new SegmentMatcher('<n:integer>'); // 只匹配整数 // ❌ 不好的做法 const matcher = new SegmentMatcher('<n:text>'); // 匹配文本后转换
常见问题
空格相关
Q: 为什么我的模式无法匹配? A: 检查空格是否完全匹配。模式中的每个空格都必须在输入中有对应的空格。
类型相关
Q: 为什么参数类型不正确? A: 确保使用了正确的类型声明,并在必要时使用类型断言。
性能相关
Q: 如何提高匹配性能? A:
- 重用匹配器实例
- 使用适当的字段映射
- 避免不必要的类型检查
- 使用缓存机制
调试技巧
查看令牌
typescript
const matcher = new SegmentMatcher('pattern');
console.log(matcher.getTokens()); // 查看解析后的令牌检查匹配结果
typescript
const result = matcher.match(segments);
console.log({
matched: result?.matched,
params: result?.params,
remaining: result?.remaining
});