将单词定义为连续的字符块

pyparsing definition of a word as contiguous block of chars

我正在尝试从以下示例行中提取 ID 和数据。 我将 id 定义为包含字母数字和一些其他字符但不包括逗号的东西。我希望 pyparsing 不会将数据的数字 1 作为 id 的一部分,因为数据是连续的块,其中包括逗号,并且逗号被排除在 id 之外。 pyparsing 不应该拒绝整个数据部分作为 id,因为该连续数据块包含 id 部分中未定义的其他字符吗?我的期望是规则适用于整个单词而不是单词

joinTokensViaSpace = lambda tokens: " ".join(" ".join(t.split()) for t in tokens)
parser= OneOrMore(Word(alphanums+'-/.'))('id').setParseAction(joinTokensViaSpace) + Word(nums+',.()')('data') 
parser.parseString('                    XXX Y/123          1,234.567890')

输出我得到

(['XXX Y/1231', ',234.567890'], {'data': [(',234.567890', 1)], 'id': [('XXX Y/1231', 0)]})

我期望的输出 (['XXX Y/123', '1,234.567890'], {'data': [('1,234.567890', 1)], 'id': [('XXX Y/123', 0)]})

一般来说 Word 通常会在空格上进行解析,但并不像您所发现的那样得到保证。我尝试稍微更改您的解析器以添加 Word's optional asKeyword=True argument, and also using Regex with surrounding \b markers, but in both cases, the ',' in 1,234.567890 满足正常的分词行为。

最简单的解决方案是在匹配 Word(alphanums+'-/.'):

之前,在 OneOrMore 中插入否定前瞻
number = Word(nums+',.()')
parser= OneOrMore(~number + Word(alphanums+'-/.'))('id')\
            .setParseAction(joinTokensViaSpace) + number('data')

这样,在开始另一个 Word 之前,解析器首先检查它是否处于潜在的 number,只有在没有的情况下才继续。通过此更改,解析后的输出将如您所愿。 (也许我应该向 OneOrMoreZeroOrMore 添加一个 stopOn 参数,例如 OneOrMore(Word(alphanums+'-/.'), stopOn=number) - 这对于 pyparsing 开发人员来说确实是一个非常常见的陷阱。)

我还看到您正在使用结果名称 - 这是一个养成的好习惯。既然你有它们,我建议你使用 dump() 作为检查 parseString.

返回的 ParseResults 结构的最佳工具
result = parser.parseString('                    XXX Y/123          1,234.567890')
print result.dump()

打印

['XXX Y/123', '1,234.567890']
- data: 1,234.567890
- id: XXX Y/123