Pyparsing 学习笔记(一)

pyparsing module ——定义和执行语法分析的类和方法

相对于传统的Lex/Yacc方法或者正则表达式,Pyparsing提供了一个创建和执行简单的语法的替代方案。有了Pyarsing,你不需要学习新的句法来定义语法或者匹配表达式。你可以直接在Python环境中使用Pyparsing提供的类库来构造语法。

下面是一段用来解析 “Hello, World!” (或任何类似形式 "<招呼语>,<招呼对象>!")的程序。这个段程序使用了Word, Literal, 和And 元素 ('+' 操作符创建 And 表达式, 字符串被自动地转换成 Literal 表达式):

from pyparsing import Word, alphas
# define grammar of a greeting
greet = Word(alphas) + "," + Word(alphas) + "!"
hello = "Hello, World!"
print(hello, "->", greet.parseString(hello))

程序输出下面的结果:

Hello, World! -> ['Hello', ',', 'World', '!']

得益于自解释性的类名,以及使用‘+’, ‘|’ 和 ‘^’ 之类的操作符,用Pyparsing构造的语法表示具有很好的可读性。

ParserElement.parseString 返回的ParseResults对象可以通过嵌套列表,字典或者命名的对象来访问。

Pyarsing模块内部已经处理了下面几个问题,这些都是在开发文本解释器时会碰到的令人恼火的典型问题:

  • 多了或者少了空格(上面的程序可以处理 “Hello,World!”, “Hello , World !”, 等等。)
  • 引用的字符串
  • 内嵌的注释行

 
 


开始使用 Pyparsing —


ParserElementParseResults 是Pyparsing的两个基类,其他大部分子类都是从这两个基类继承来的。我们使用后续的例子来理解这两个基类的功能:

 
 


class pyparsing.And(exprs, savelist=True)
  Bases: pyparsing.core.ParseExpression


要求按照给定的顺序找出给定的 ParseExpression 表达式。表达式之间可以被空格分隔。相同的构造可以使用'+'操作符来实现。也可以使用'-'来构造,这个操作符抑制回溯。???

例子:

integer = Word(nums)
name_expr = OneOrMore(Word(alphas))

expr = And([integer("id"), name_expr("name"), integer("age")])
# more easily written as:
expr = integer("id") + name_expr("name") + integer("age")

checkRecursion(parseElementList)
parseImpl(instring, loc, doActions=True)
streamline()
 
 


class pyparsing.CaselessKeyword(matchString, identChars=None)
  Bases: pyparsing.core.Keyword


关键字类 Keyword的不关心大小写的版本.

例子:

OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD']

(对照 CaselessLiteral.)

 
 


class pyparsing.CaselessLiteral(matchString)
  Bases: pyparsing.core.Literal


配置特定的字符串,忽略字母大小写格式。注意:匹配结果跟给定的匹配图样大小写一致,跟被匹配的字符串大小写无关。

例子:

OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD']

(对照 CaselessKeyword.)
parseImpl(instring, loc, doActions=True)

 
 


class pyparsing.CharsNotIn(notChars, min=1, max=0, exact=0)
  Bases: pyparsing.core.Token


Token for matching words composed of characters not in a given set (will include whitespace in matched characters if not listed in the provided exclusion set - see example). Defined with string containing all disallowed characters, and an optional minimum, maximum, and/or exact length.
构造一个令牌,用于匹配特定的单词。这些单词由不在给定集合中的字符组成。由这些单词组成的字符串包含所有不允许字符,字符串可选指定最小,最大和确定长度选项。min 的默认值是 1 小于 1 的值非法);maxexact 的默认值是 0,表示没有最大和确定的长度限制。
(如果空格符不在给定的例外集合里面,在匹配的字符中会包含空格符。参考下面的例子。)

例子:

# define a comma-separated-value as anything that is not a ','
csv_value = CharsNotIn(',')
print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213"))

输出结果:

['dkls', 'lsdkjf', 's12 34', '@!#', '213']

parseImpl(instring, loc, doActions=True)

 
 


class pyparsing.Combine(expr, joinString='', adjacent=True)
  Bases: pyparsing.core.TokenConverter


用来把所有匹配的令牌连接成单一字符串的转换器。默认情况下,匹配图样在输入字符串中也必须是相邻的。可以在构造器中指定'adjacent=False'来关闭这个默认特性。

例子:

real = Word(nums) + '.' + Word(nums)
print(real.parseString('3.1416')) # -> ['3', '.', '1416']
# will also erroneously match the following
print(real.parseString('3. 1416')) # -> ['3', '.', '1416']

real = Combine(Word(nums) + '.' + Word(nums))
print(real.parseString('3.1416')) # -> ['3.1416']
# no match when there are internal spaces
print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...)

ignore(other)[]
Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns.

例子:

patt = OneOrMore(Word(alphas))
patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj']

patt.ignore(cStyleComment)
patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd']

postParse(instring, loc, tokenlist)

 
 


class pyparsing.Dict(expr)
  Bases: pyparsing.core.TokenConverter


转换器,用于把一个多次重复的表达式匹配结果返回成一个列表和字典。每一个元素可以使用表达式中的第一个令牌作为Key来访问。

例子:

data_word = Word(alphas)
label = data_word + FollowedBy(':')
attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))

text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))

# print attributes as plain groups
print(OneOrMore(attr_expr).parseString(text).dump())

# instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names
result = Dict(OneOrMore(Group(attr_expr))).parseString(text)
print(result.dump())

# access named fields as dict entries, or output as dict
print(result['shape'])
print(result.asDict())

输出结果:

['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap']
[['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
- color: light blue
- posn: upper left
- shape: SQUARE
- texture: burlap
SQUARE
{'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'}

 
未完待续,请参考下一节 Pyparsing学习笔记(二)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容