有没有一种简单的方法在pyparsing中添加自定义错误消息?

huangapple go评论72阅读模式
英文:

Is there an easy way to add custom error messages in pyparsing?

问题

Sure, here's the translated portion of your text:

假设我们有一个语法,其中存在一个预期但未找到的元素。假设回溯被禁用,即该元素之前带有一个“-”符号。

在库中是否有一种设置自定义错误消息的方法,比如“需要Foo”,在该元素上?或者是捕获解析异常并使用位置信息来处理它的唯一方法?

说:

from pyparsing import *

grammar = (
    Literal("//")
    - Word(alphanums)("name")
    + Suppress(White()[1,...])
    + Word(alphanums)("operation")
).leave_whitespace()

grammar.run_tests("""
//name op
// opnoname
""", print_results=True)

第2行的输出是:

// opnoname
  ^
ParseException: 期望的 W:(0-9A-Za-z),找到 ' ' (在字符2处),(行:1,列:3)
FAIL: 期望的 W:(0-9A-Za-z),找到 ' ' (在字符2处),(行:1,列:3)

我想要一个自定义消息,例如“需要name”而不是通用的“期望的 W:(0-9A-Za-z),找到 ' '”。

到目前为止,捕获ParseException,修改其中的message,然后重新引发它似乎是一种解决方法。我是否漏掉了更基本的东西?


对于那些感兴趣的人:这在编写JCL(作业控制语言)解析器时出现了。

我目前使用的是最新的pyparsing稳定版本:3.0.9。

英文:

Suppose we have a grammar where there is an element that was expected but is not found. Assume that the backtracking is disabled, i.e. the element is preceded by a - sign.

Is there any way in the library to set a custom error message, such as "Foo was needed", on that element? Or is the only way to catch the parse exception and work it out using the location information?

Say:

from pyparsing import *

grammar = (
    Literal("//")
    - Word(alphanums)("name")
    + Suppress(White()[1,...])
    + Word(alphanums)("operation")
).leave_whitespace()

grammar.run_tests("""
//name op
// opnoname
""", print_results=True)

The output for the 2nd line is:

// opnoname
  ^
ParseException: Expected W:(0-9A-Za-z), found ' '  (at char 2), (line:1, col:3)
FAIL: Expected W:(0-9A-Za-z), found ' '  (at char 2), (line:1, col:3)

I'd like a custom message, such as "name was needed" instead of the generic "Expected W:(0-9A0Za-z), found ' '".

So far it looks like catching the ParseException, modifying the message in it, and re-rasising it would be a solution. Am I missing something more fundamental?


For those curious: this came up when writing a JCL (Job Control Language) parser.

I'm using latest pyparsing stable version at the moment: 3.0.9.

答案1

得分: 1

以下是翻译好的内容:

它们不是自定义错误消息,但您可以使用set_name为语法的不同元素提供漂亮的名称。

请注意set_nameset_results_name之间的区别。
set_name为表达式本身赋予名称,而
set_results_name(在使用
expr("name")符号时会隐式调用)是分配名称给解析结果的方式。

如果要生成铁路图,并添加show_results_names=True

我一直希望pyparsing在可以的情况下处理空格,而不是在我的语法中明确显示它。
如果要强制不允许在前导“//”和“name”标识符之间存在空格,可以这样写:

Pyparsing的隐式空格跳过会处理名称和操作之间的空格。name上的leave_whitespace告诉pyparsing在解析name标识符之前不跳过空格。但是,您可能对此语法的其他部分有其他计划,所以由您决定采用哪种方式。

我很高兴看到您正在使用run_tests!这是一个提示:您可以在测试中插入注释,它们将显示为输出中每个测试的标签,就像这样:

您还可以在测试之间插入空白行以提高可读性,就像在Python代码中插入空行一样。

英文:

They aren't custom error messages, but you can use set_name to give nice
names to the different elements of your grammar.

identifier = Word(alphanums).set_name("identifier")
grammar = (
    Literal("//")
    - identifier("name")
    + White().suppress()
    + identifier("operation")
).leave_whitespace()
grammar.set_name("grammar")

Note the difference between set_name and set_results_name.
set_name gives a name to the expression itself, while
set_results_name (which you implicitly call when using the
expr("name") notation) is what assigns names to the parsed
results.

It is easier to see the distinction if you generate a
railroad diagram, and add show_results_names=True:

grammar.create_diagram("grammar.html", show_results_names=True)

有没有一种简单的方法在pyparsing中添加自定义错误消息?

I've always wanted to let pyparsing deal with whitespace
when I can, and not explicitly show it in my grammar.
If you want to enforce no spaces between the leading '//'
and the name identifier, you can write like this:

grammar = (
    Literal("//")
    - identifier("name").leave_whitespace()
    + identifier("operation")
)

Pyparsing's implicit whitespace skipping will take care
of the spaces between name and operation. leave_whitespace
on the name alone tells pyparsing not to skip whitespace
before parsing the name identifier. But you may have other
plans for further parts of this grammar, so I'll leave it
up to you which way to go on this.

I'm glad to see you are using run_tests! Here is a tip: you
can insert comments in your tests, and they will show up as
labels for each test in your output, like this:

grammar.run_tests("""\
# successful expression
//name op
# more than one space between name and operation - still works!
//name   op
# failing expression, missing second identifier
// opnoname
# failing expression, name but no operation
//namenoopn
# failing expression, space after '//'
// name op
""")

and get this output:

# successful expression
//name op
['//', 'name', 'op']
- name: 'name'
- operation: 'op'

# more than one space between name and operation - still works!
//name   op
['//', 'name', 'op']
- name: 'name'
- operation: 'op'

# failing expression, missing second identifier
// opnoname
// opnoname
  ^
ParseSyntaxException: Expected identifier, found ' '  (at char 2), (line:1, col:3)
FAIL: Expected identifier, found ' '  (at char 2), (line:1, col:3)

# failing expression, name but no operation
//namenoopn
//namenoopn
           ^
ParseSyntaxException: Expected identifier, found end of text  (at char 11), (line:1, col:12)
FAIL: Expected identifier, found end of text  (at char 11), (line:1, col:12)

# failing expression, space after '//'
// name op
// name op
  ^
ParseSyntaxException: Expected identifier, found ' '  (at char 2), (line:1, col:3)
FAIL: Expected identifier, found ' '  (at char 2), (line:1, col:3)

You can also insert blank spaces between tests for readability,
just like you would insert blank lines in your Python code.

huangapple
  • 本文由 发表于 2023年5月18日 04:08:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76275859.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定