@atomist/微缩图
正在解析库中 类型脚本,填补巨大的空白 介于正则表达式的甜点和全响之间 银行 或等同的语法. 它可以分析 和干净地更新 结构化内容.
概念
微语法 是分析结构化内容的有力方式 如源代码,在此描述 斯坦福论文。 。 。 . 微语法旨在识别字符串中的结构或 流并提取其内容: 例如, 要识别 Java 具有特定注释和提取特定 参数。 他们更强大 比较一般 可读 比起来 正则表达式 用于复合体 例,尽管可以使用正则表达式构建.
原子学家的微语法超越了斯坦福的论文例子 他们允许 更新 以及匹配,保留位置。 他们 也从其他经验和来源,例如: 旧 SNOBOL 编程语言。 。 。 .
实例
有两种使用方式:
- 从 定义: 在 JavaScript 中定义代表子组件的语法对象( 低等出品)
- 从字符串:在类似输入的字符串中定义语法 将匹配
微语法有一个由定义定义的回回类型. 每个匹配执行此接口以及 PatternMatch 界面,它暴露出输入和匹配值中的偏移值,可能与被输入值不同。 (例如,a Person 可能有一个 forename 财务报告和审定财务报表 surname,但其 $matched 值可能包括整个匹配的有白空间的字符串。 ) 田园 PatternMatch 界面从一个 $ 以确保他们脱离乐队.
当定义了微语法时,可以使用它来匹配输入:通常是字符串.
发电机式的迭代通常效率最高,看起来是这样:
const matches = myMicrogrammar.matchIterator(inputString);
for (const match of matches) {
// Do with match. You can jump out of the generator here.
}
你也可以得到所有匹配 在一个通行证,像这样:
const matches = myMicrogrammar.findMatches(inputString);
for (const match of matches) {
// Do with match
}
如果您只想要一个匹配, 您可以使用返回匹配的方法 undefined,内容如下:
const match = myMicrogrammar.firstMatch(inputString);
if (match) {
// Do with match
}
定义样式
这里有一个简单的例子:
const mg = microgrammar<{name: string, age: number}>({
name: /[a-zA-Z0-9]+/,
_col: ":",
age: Integer
});
const results = mg.findMatches("-celine:61 greg*^ tom::: mandy:11");
assert(result.length === 2);
const first = results[0];
assert(first.$matched === "celine:61");
// The offset of this match was the 1st character, as the 0th was discarded
assert(first.$offset === 1);
assert(first.name === "celine");
assert(first.age === 61);
一些说明:
- 微语法定义一般为对象字面,带有 属性依次匹配。 这就像 协和 在一个BNF语法.
- 匹配属性值可以是正则表达式( 如
/[a-zA-Z0-9]+/这里),字符串正文(如:),或习惯 匹配者( 如Integer) (中文(简体) ). 很容易定义自定义匹配者 用于构成. - 所有属性都需要匹配整个微语法才能匹配.
- 匹配的属性与结果相接, 除非它们的名字开始于
_时 复数. - 带值中的某些值, 首先
$,添加到 结果,显示匹配的准确文本、相抵等. - 在使用TypeScript时,微语法返回可以被强烈地打入. 在这种情况下,我们已经 使用匿名类型, 但我们也可以使用接口 。 我们 也可以使用未打字的JavaScript样式.
- 匹配跳过垃圾, 如
greg*^ tom:::在这种情况下,greg财务报告和审定财务报表tom:看起来像是有效匹配的开始,但 当它不能匹配时,首先会失败:和第二个何时 结肠后面没有数字. - 我们可以比对一串或一串流。 在这种情况下,我们用 一个字符串。 在水流匹配中,我们更可能使用一个a API 提供回调而不是建立阵列, 所以我们不 需要我们所有的火柴 立即在记忆中.
当然,这样一个简单的例子可以很容易地由经常人员处理 表达和捕捉组。 但力量变得明显 筑巢出产并更精细相配.
一个更复杂的例子,显示构成:
export const CLASS_NAME = /[a-zA-Z_$][a-zA-Z0-9_$]+/;
// Any annotation we're not interested in
const DiscardedAnnotation = {
_at: "@",
_annotationName: CLASS_NAME,
_content: optional(JavaParenthesizedExpression),
};
const SpringBootApp = microgrammar<{ name: string }>({
_app: "@SpringBootApplication",
_content: optional(JavaParenthesizedExpression),
_otherAnnotations: zeroOrMore(DiscardedAnnotation),
_visibility: optional("public"),
_class: "class",
name: CLASS_NAME,
});
这符合这样的内容:
@SpringBootApplication
@Foo
@Bar(name = "Baz", magicParam = 31754)
public class MySpringBootApplication
注释:
JavaParenthesizedExpression是一个内置匹配器常数 匹配任何有效的 Java 内容(...)它使用状态 机器。 机器。 。 写这种习俗相配者很容易.- 默认情况下,微语法对白空间是宽容的,对待它 作为符号分隔符. 这是我们在分析时想要的行为 大多数语言或配置格式.
- 因为其他的属性 名字从
_,仅限 类名( e)MySpringBootApplication(以我们为例) 对结果。 我们关心其余部分的结构 类声明,但我们不需要在 这个案子.
字符串样式
这是一个更高水平的使用模式,其中的字符串类似于 需要输入但有可变占位符用于定义 语法.
这种风格最适合更简单的语法. 例如:
const ValuePredicateGrammar = microgrammar<Predicate>({
phrase: "@${name}='${value}'"});
它可以通过提供定义样式结合 指定字段的可选定义。 例如,限制 使用正则表达式进行上述示例中名称上的匹配 :
const ValuePredicateGrammar = microgrammar<Predicate>({
phrase: "@${name}='${value}'",
terms: {
name: /[a-z]+/
}
});
与对象定义样式一样,白空间默认被忽略.
进一步的文件可在以下网址查阅: 参考文献。也可以检查测试 在此仓库中.
替代品和何时使用微语法
微语法与 BNF 语法不过 一些重要方面有所不同:
- 它们是为了匹配和解释 组件 输入,而不是 而不是整个输入
- 他们很擅长跳过他们不感兴趣的内容
- 他们不一定自由的背景
- 它们不需要建造一个完整的AST,尽管它们建造 匹配结构的AST. 因此,他们很容易应付 部分结构化数据, 愉快地跳过无法理解的内容
相似之处有:
- 设想 生产
- 可编织性,包括再利用生产的能力 不同的语法
- 业务,例如 备选案文, (中文(简体) ), 选项 财务报告和审定财务报表 代表,那个 能够建立复杂的结构.
相较于正则表达式,微语法为:
- 能够提出更复杂的问题
- 更可调和
- 更高级别, 能够使用正则表达式作为构件
- 能够表达嵌入式结构
- 通过类型脚本函数上游和 自定义 匹配点
虽然使用一个微语法来做一些 可以用简单的regex表示,微语法往往更清晰 对于复杂的案件.
使用量
这个 @atomist/microgrammar 软件包 包含两个
TypeScript打字并编译了JavaScript. 您可以使用此项目
通过在您的 package.json。 。 。 .
$ npm install --save @atomist/microgrammar
解决问题
如果你努力使你的微语法吻合 请参考 排除出错的页面。 。 。 .
业绩考虑
见 写入高效的微语法。 。 。 .
支助
一般性支持问题应在缔约方会议 #support
频道 原子主义社区。 。 。 .
如果你发现问题,请创建 问题。 。 。 .
发展
您需要安装 节点.js 来建立和测试这个 项目.
构建和测试
安装依赖关系 .
$ npm install
使用 build 用于编译、测试、嵌入和构建
文档.
$ npm run build
释放
释放是通过 原子学家SDM按钮 在原子仪表板或Slack上的“证明”按钮.