[Nearley]:如何解析匹配的开始和结束标记

2024-06-20

我正在尝试用nearley 解析一种非常简单的语言:您可以在匹配的开始和结束标记之间放置一个字符串,并且可以链接一些标记。它看起来像一种 XML,但带有[代替<,标签总是 2 个字符长,并且没有嵌套。

[aa]My text[/aa][ab]Another Text[/ab]

但我似乎无法正确解析这一点,因为我得到the grammar should be unambiguous一旦我有多个标签。

我现在拥有的语法:

@builtin "string.ne"
@builtin "whitespace.ne"

openAndCloseTag[X] -> "[" $X "]" string  "[/" $X "]"

languages -> openAndCloseTag[[a-zA-Z] [a-zA-Z]] (_ openAndCloseTag[[a-zA-Z] [a-zA-Z]]):*

string -> sstrchar:* {% (d) => d[0].join("") %}

相关的是,理想情况下我希望标签不区分大小写(例如[bc]TESt[/BC]将是有效的)

有谁知道我们该如何做到这一点?我找不到附近的 XML 解析器示例。


您的语言几乎太简单了,不需要解析器生成器。同时,它不是上下文无关的,这使得解析器生成器的使用变得困难。因此,Nearly 解析器很可能不是最适合您的工具,尽管可能需要一些技巧才能使其工作。

首先要事。您实际上并没有提供您的语言的明确定义,这就是您的解析器报告歧义的原因。要查看歧义性,请考虑输入

[aa]My text[/ab][ab]Another Text[/aa]

这与您的测试输入非常相似;我所做的只是交换一对字母。现在,问题是:这是一个由单个组成的有效输入吗?aa标签?或者是语法错误? (这是一个严肃的问题。像这样的标签系统的一些定义认为标签只能由匹配的关闭标签关闭,因此看起来像不同标签的东西被认为是纯文本。这样的系统将接受输入作为单个标记值。)

问题是你定义了string as sstrchar:*,如果我们看一下定义sstrchar in string.ne https://github.com/kach/nearley/blob/master/builtin/string.ne,我们看到(忽略不相关的后处理操作):

sstrchar -> [^\\'\n]
    | "\\" strescape
    | "\\'"

现在,第一种可能性是“除反斜杠、单引号或换行符之外的任何字符”,并且很容易看出中的所有字符[/ab] are in sstrchar。 (我不清楚你为什么选择sstrchar;单引号在您的语言中似乎并不特殊。或者也许你只是没有提到它们的重要性。)所以string可以延伸到输入的末尾。当然,该语法需要结束标记,并且如果有的话,Nearley 解析器会确定查找匹配项。但事实上,有两个。因此解析器声明了一个歧义,因为它没有任何标准在两个关闭标记之间进行选择。

这就是我们遇到的问题,即您的语言不是上下文无关的。 (实际上,从某种技术意义上来说,它是上下文无关的,因为“只有”676 个不区分大小写的两个字母的标签,理论上可以列出所有 676 种可能性。但我猜你不希望要做到这一点。)

上下文无关语法无法表达坚持两个非终结符扩展为同一字符串的语言。这就是上下文无关的定义:如果一个非终端只能匹配与前一个非终端相同的输入,那么 第二个非终结符匹配取决于上下文,特别是第一个非终结符产生的匹配。在上下文无关语法中,无论文本的其余部分如何,非终结符都会扩展为相同的内容。非终结符出现的上下文不允许影响扩展。

现在,您很可能期望您的宏定义:

openAndCloseTag[X] -> "[" $X "]" string  "[/" $X "]"

通过重复来表达上下文相关的匹配$X宏参数。但是,Nearley 文档将这种构造描述为宏并非偶然。X这里指的是宏调用中使用的字符串。所以当你说:

openAndCloseTag[[a-zA-Z] [a-zA-Z]]

近乎宏将其扩展为

 "[" [a-zA-Z] [a-zA-Z] "]" string  "[/" [a-zA-Z] [a-zA-Z] "]"

这就是它将用作语法产生式的内容。观察两者$X宏参数已扩展为相同的参数,但这并不意味着将匹配相同的输入文本。每个子模式都将独立匹配任意两个字母字符。与上下文无关。

正如我之前提到的,您可以使用此宏写出 676 种可能的标记模式:

tag -> openAndCloseTag["aa"i]
     | openAndCloseTag["ab"i]
     | openAndCloseTag["ac"i]
     | ...
     | openAndCloseTag["zz"i]

如果你这样做了(并且你成功地正确列出了所有可能性),那么解析器就不会抱怨歧义只要您永远不会在同一输入中使用同一标签两次。因此,您的原始输入和我更改后的输入都可以(只要您接受我的输入是单个标记对象的解释)。但它仍然会报告以下内容不明确:

[aa]My text[/aa][aa]Another Text[/aa]

这是不明确的,因为语法允许它是一个单一的aa带标签的字符串(其文本包含看起来像关闭标签和打开标签的字符)或作为两个连续的aa标记的字符串。

为了消除歧义,您必须编写string以不允许内部标签的方式进行模式,就像sstrchar不允许内部单引号。当然,匹配不包含模式的字符串并不比匹配不包含单个字符的字符串那么简单。可以使用 Nearley 来完成,但我真的不认为这是你想要的。

也许你最好的选择是使用原生 Javascript 正则表达式来匹配标记的字符串。这将被证明更简单,因为 JavaScript 正则表达式比数学正则表达式更强大,甚至允许匹配(某些)上下文相关结构的可能性。例如,您可以将 Javascript 正则表达式与 Moo 词法分析器一起使用,它可以很好地集成到 Nearley 中。或者您可以直接使用正则表达式,因为一旦匹配了标记的文本,您就不需要做太多其他事情了。

为了帮助您入门,这里有一个简单的 Javascript 正则表达式,它将标记的字符串与匹配的不区分大小写的标签(i标志在最后):

/\[([a-zA-Z]{2})\].*?\[\/\1\]/gmi

您可以使用它在线玩正则表达式101 https://regex101.com/r/Z9U0s1/1

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[Nearley]:如何解析匹配的开始和结束标记 的相关文章

随机推荐

  • 如何从谷歌表格下载 PNG 图表

    我试图在 Google Sheet 中创建一个自定义菜单 以允许我将当前 Google Sheet 文件中所有工作表中的所有图表下载到 PNG 图像中 使用图表标题作为图像名称 保存到我的 Windows PC 的默认下载目录中 我打算使用
  • sbt 项目构建中的多个目标目录

    我有一个这样结构的 sbt 项目 build sbt project build properties plugins sbt src main java smcho App java test java smcho AppTest jav
  • 如何在响应ajax codeigniter后停止执行其他控制器

    我想知道如何在响应输出 json 数据后停止执行函数和涉及的其他控制器 就我这里的情况而言 我只是打电话test 函数于dashboard控制器 In dashboard构造函数将执行MY Login library In MY Login
  • flash 10 正交投影

    我一直在尝试新的 flash 10 3d 可能性 发现在 3d 中旋转精灵相当容易 var card Sprite new MyCard card x 100 card y 100 card z 200 card rotationX 60
  • 如何使用正则表达式验证带有可选百分比符号的小数?

    正如问题的标题 我需要使用以下值验证正则表达式 最多 2 个小数位和 9 个整数 带有可选的百分比符号 Valid 10 0 1111111 12 15 2 10 2 3 Invalid 12 02 123456789123 123 I t
  • readLine() 只读取控制台中的第二个输入

    我刚刚开始使用 Kotlin 所以如果这是一个愚蠢的问题 我认为这可能是 我深表歉意 我正在跟进this https kotlinlang org docs tutorials jvm get started html指南 但遇到了一个问题
  • 仅头文件库的优点

    仅头文件库有哪些好处 为什么要以这种方式编写它而不是将实现放入单独的文件中 仅标头库的优点 简化构建过程 您不需要构建库 也不需要在构建的链接步骤中指定编译的库 如果您确实有一个已编译的库 您可能想要构建它的多个版本 一个在启用调试的情况下
  • 在 NDB 和 GAE 中的 put() 之后评估条件

    在将实体放入数据存储区后 我需要使用 NDB 执行一些代码 假设我有这样的东西 ent Entity ent put def after put assert 如何在不手动调用该函数的情况下实现这一目标 我可以使用某种触发器或回调吗 是的
  • 是否可以将 ECMAScript 6 生成器重置为其初始状态?

    给定提供的 非常简单 生成器 是否可以将生成器返回到其原始状态以再次使用 var generator function yield 1 yield 2 yield 3 var iterable generator for let x of
  • 如何制作带有 SWIFT 图像的弹出窗口

    我想知道如何制作类似于此示例的弹出窗口 原始窗口充满了按钮 选择这些按钮后将拉出我想要使用的图像 我会简单地创建一个可重用的UIView组件以及作为子视图所需的一切 例如UIImageView为了你的形象 UILabel or a UIBu
  • Flask wtforms selectfield 选择不更新

    class ArticleForm Form type SelectField type choices h id h name for h in ArticleType query all coerce int 下面是我如何在视图中使用
  • 检查 PHP 中“@”字符后面的单词

    我现在正在制作一个新闻和评论系统 但是我已经在一个部分上停留了一段时间了 我希望用户能够在 Twitter 上引用其他玩家的风格 例如 用户名 该脚本看起来像这样 不是真正的 PHP 只是想象脚本 3 string I loved the
  • 将数字范围拆分为特定数量的间隔

    我有一个间隔 0 max 我想将其分成特定数量的子区间 为此 我编写了一个函数 名为getIntervalls max nbIntervals where max是我的第一个间隔中的最大元素 nbIntervals是预期子区间的数量 例如
  • 如何绑定div宽度/高度来形成字段?

    我想创建多个div我可以移动和调整大小 并绑定它们width height等到数组中的对象 因此 如果我创建六个 div 我的数组中有六个对象 每个对象都有 width height etc 我不太明白如何使用 knockout js 将输
  • 我可以在 CSS 类名中使用驼峰命名法吗

    我想命名一个 CSS 类并调用它imgSuper 我可以在 CSS 类中使用驼峰命名法吗 从技术上讲是可以的 但这是有风险的 因为虽然 CSS 语法大多不区分大小写 但在某些浏览器中 在某些条件下 类名被视为区分大小写 因为规范没有指定浏览
  • 如何从 SDK 实现每个会话的 Google Places 自动完成功能?

    是否可以从 Android 和 iOS 应用程序的 place sdk 实现基于会话的自动完成 根据 6 月 11 日生效的新 Google 地图框架定价 对自动完成的请求可以分为基于击键 会话的请求 我找不到描述实施步骤的文档 除了这个参
  • 获取带有计数的不同记录

    我有一张桌子personid and msg列 personid msg 1 msg1 2 msg2 2 msg3 3 msg4 1 msg2 我想得到总计msg对于每个personid 我正在尝试这个查询 select distinct
  • Qt 5.3 QPlainTextEdit 更改 QTextCursor 颜色

    我想更改下面的光标颜色QPlainTextEdit小部件 我能够将其宽度设置为6 但我想改变颜色或者它 是否可以 QFontMetrics fm font setCursorWidth fm averageCharWidth setCurs
  • 为什么我收到“找不到 com.android.tools.build:gradle”错误?

    这是基于我最后的question https stackoverflow com questions 30958596 how to resolve low sdk build tools error以及 按照此tutorial https
  • [Nearley]:如何解析匹配的开始和结束标记

    我正在尝试用nearley 解析一种非常简单的语言 您可以在匹配的开始和结束标记之间放置一个字符串 并且可以链接一些标记 它看起来像一种 XML 但带有 代替 lt 标签总是 2 个字符长 并且没有嵌套 aa My text aa ab A