ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python – pyparsing中的可选字符串段

2019-06-20 22:42:52  阅读:173  来源: 互联网

标签:python pyparsing


我正在使用pyparsing并尝试定义两个项目,如下所示:

identifier = Word(alphas, alphanums).setName('identifier)

database_name = Optional(identifier.setResultsName('user') + Suppress('.')) + identifier.setResultsName('database')
table_name = database_name + Suppress('.') + identifier.setResultsName('table')

这个想法是匹配table_name,它将采用一个包含两个或三个段的字符串,并产生以下结果:

mark.foo.bar
=> tokens.user = 'mark'
   tokens.database = 'foo'
   tokens.table = 'bar'

或者如果缺少第一个段:

foo.bar
=> tokens.user = ''  #anything is acceptable: none, empty string or just plain missing
   tokens.database = 'foo'
   tokens.table = 'bar'

table_name应始终具有两个段和一个点,或者如上所述的三个段(两个点).一段是不可接受的.

database_name应该有一个段(数据库)或两个(user.database).

使用database_name的实例工作正常 – 它将在一个或两个段上匹配.但是,table_name在某些情况下失败:

# Works for three segments
mark.foo.bar
=> tokens.user = 'mark'
   tokens.database = 'foo'
   tokens.table = 'bar'

# Fails for two
foo.bar
=> Expected "." (at char 7), (line:1m col:8)

我可以看到它正在做什么:foo.bar已经与user.database匹配,现在它正在期待代表表名的第三个块.然而它不是我想要的.

救命?

解决方法:

问题是,当你匹配前导标识符时,你不知道它是否会成为用户字段,直到你查看了所有可能的表字段.遗憾的是,这意味着您无法使用其主要的可选“用户”字段定义数据库名称,您必须定义一个包含两个或三个字段的综合table_name表达式.

以下代码显示了3个用于解决主要可选标识符的歧义的选项:

>首先尝试匹配完整的3字段表单,如果失败,请尝试匹配2字段表单
>在匹配可选的前导’用户’字段时明确地预测,使用FollowedBy仅匹配’用户’,如果后跟2 *(DOT标识符)
>匹配任何长度的所有以点分隔的列表,并使用解析操作来验证是否只传递了2或3个标识符,并分配结果名称

请参阅注释以了解每个选项的实现方式. (注意,为了简化代码,我还将完整的expr.setResultsName(‘something’)替换为expr(‘something’),我认为总体上更容易阅读.)

from pyparsing import *

identifier = Word(alphas, alphanums).setName('identifier')
DOT = Suppress('.')

# Option 1 - fully specified options
full_database_name = identifier('user') + DOT + identifier('database')
just_database_name = identifier('database')
table_name = (full_database_name + DOT + identifier('table') | 
              just_database_name + DOT + identifier('table'))

# Option 2 - use FollowedBy to explicitly lookahead when checking for leading user
table_name = (Optional(identifier('user') + FollowedBy(2*(DOT+identifier)) + DOT) + 
                identifier('database') + DOT + identifier('table'))

# Option 3 - use liberally matching expression, with a parse action to assign fields
def assignTableFields(fields):
    if len(fields) == 2:
        fields['database'],fields['table'] = fields
    elif len(fields) == 3:
        fields['user'],fields['database'],fields['table'] = fields
    else:
        raise ParseException("wrong number of fields")
table_name = delimitedList(identifier, delim='.').setParseAction(assignTableFields)

for test in ("a.b.c", "b.c"):
    print test
    print table_name.parseString(test).dump()
    print

你也可能会发现这个过度自由的匹配器,因为它也允许交错的空格,因此“a.b”也有资格作为有效的表名.您可以定义另一个验证解析操作,并将其添加到table_name:

def noWhitespace(source, locn, tokens):
    if not source[locn:].startswith('.'.join(tokens)):
        raise ParseException("found whitespace between fields")
table_name.addParseAction(noWhitespace)

请注意,对于此解析操作,我调用了addParseAction而不是setParseAction,以便保留任何现有的解析操作(在选项3的情况下),并将此新的操作添加到要运行的解析操作链中.

标签:python,pyparsing
来源: https://codeday.me/bug/20190620/1249148.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有