【问题标题】:Grammar - How to match optional and required whitespaces before and after words?语法 - 如何在单词前后匹配可选和必需的空格?
【发布时间】:2020-11-24 18:57:43
【问题描述】:

我正在使用nearley and moo 提出一个相当复杂的语法。除了我的空白要求之外,它似乎工作正常。我需要在需要时要求空格,并在不需要时允许它,同时保持语法明确。

例如:

After dinner, I went to bed.

我需要在单词之间使用空格,但允许在逗号周围使用空格。所以以下也是有效的:

After dinner , I went to bed.
After dinner,I went to bed.

下面是一个快速的近乎语法试图做到这一点。 如果你不明白语法,很容易弄清楚。

// Required whitespace
rws : [ \t]+
// Optional whitespace
ows : [ \t]*

sentence -> words %ows "," sentence
          | words

words    -> word %rws words
         -> word

word     -> [a-zA-Z]

语法可能有问题,但想法是一样的。这变成了一个模棱两可的语法。如何定义明确的语法,期望可选和必需的空格?

【问题讨论】:

  • 我对 Nearly 和 Moo 都不熟悉,但正则表达式可能是 whitespace : (?:[ \t]*,[ \t]*|[ \t]),而你的语法会变成 word %whitespace word。希望这是有道理的,我并没有完全搞砸语言。
  • 哦哦。没有考虑到这一点。什么是初始?:
  • 这是一个非捕获组。不确定它是否在这里相关。可能会使用([ \t]*,[ \t]*|[ \t]) 甚至只是[ \t]*,[ \t]*|[ \t]。如果你允许单词之间有多个空格,那么[ \t]*,[ \t]*|[ \t]+ 就可以了
  • 哪一个对你有用?我可以把它变成一个答案,如果你愿意,你可以接受它
  • 我在第一个建议中去掉了?:。继续发布吧。

标签: regex nearley moo-lexer


【解决方案1】:

我发现使用 可以让我的语法更简单,因此我通常会花费更少的时间来修复不明确的语法。

我不是语法设计专家,但我会这样做:

lexer.js

  • word 将匹配一个字符序列
  • comma 将匹配 " , "" ,"", "","
  • space 将匹配单个空格 " "
  • period 将匹配单个句点 "."
  • nl 将匹配一个或多个换行符。
const moo = require('moo');

const lexer =
  moo.compile
    ( { word: /[a-zA-Z]+/
      , comma:/ ?, ?/
      , space: / /
      , period: /\./
      , nl: {match: /\n+/, lineBreaks: true}
      }
    );

module.exports = lexer;

grammar.ne

我们说:

  1. 文本包含一个或多个句子
  2. 每句前后都可以出现换行符
  3. 一个句子可能%word的序列开头,后跟%comma%space并且必须以%word结尾,后跟%period.

所有的后处理规则都是扁平化的标记列表,并从标记中提取.value,以便我们最终得到单词列表。

@{% const lexer = require("./lexer.js"); %}
@lexer lexer

text
  -> %nl sentence:+ {% ([_, sentences]) => sentences %}

sentence
  -> seq:* %word %period %nl {% ([seq, w, p, n]) => [...seq, w.value] %}

seq
  -> (%word %space) {% ([[w]]) => w.value %}
   | (%word %comma) {% ([[w]]) => w.value %}

这个语法允许解析这个文本:


After breakfast, I went to work.

After lunch , I went to my desk.

After the pub,I went home.

sleep.

例子:

const nearley = require('nearley');
const grammar = require('./grammar.js');

const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));

parser.feed(`

After breakfast, I went to work.

After lunch , I went to my desk.

After the pub,I went home.

sleep.
`);

if (parser.results.length > 1) throw new Error('grammar is ambiguous');
JSON.stringify(parser.results[0], null, 2);

输出:

[
  [
    "After",
    "breakfast",
    "I",
    "went",
    "to",
    "work"
  ],
  [
    "After",
    "lunch",
    "I",
    "went",
    "to",
    "my",
    "desk"
  ],
  [
    "After",
    "the",
    "pub",
    "I",
    "went",
    "home"
  ],
  [
    "sleep"
  ]
]

【讨论】:

    【解决方案2】:

    我不熟悉 Nearly 和 Moo,但正则表达式可能是

    whitespace : ([ \t]*,[ \t]*|[ \t])
    

    你的语法会变成

    word %whitespace word
    

    希望这是有道理的,我并没有完全搞砸语言。

    【讨论】:

      猜你喜欢
      • 2017-08-23
      • 1970-01-01
      • 1970-01-01
      • 2019-04-04
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-10
      相关资源
      最近更新 更多