python - Python中字符串的复杂解析

标签 python string parsing

我想解析一个格式如下的字符串:

[{text1}]{quantity}[{text2}]

这个规则意味着在开头有一些文本可以选择存在与否,然后是一个{quantity},我在下面描述了它的语法,然后是更多可选文本。

{quantity}可以有多种形式,{n}可以是任意正整数

{n}
{n}PCS
{n}PC
{n}PCS.
{n}PC.
Lot of {n}

另外,它应该接受这个额外的规则:

{n} {text2} 

在此规则中,{n} 后跟一个空格,然后是 {text2}

在出现PC或PCS的情况下

  • 后面可以跟一个点,也可以不跟
  • 不区分大小写
  • 可以选择在 {n} 和 PCS 之间出现一个空格
  • 以下全部去掉:PC 或 PCS、可选的点和可选的空格

期望的输出被归一化为两个变量:

  • {n} 为整数
  • [{text1}] [{text2}],即第一个 {text1}(如果存在),然后是一个空格,然后是 {text2}(如果存在),连接成一个字符串。仅当有两个文本片段时才使用空格分隔文本片段。

如果 {quantity} 包含除正整数以外的任何内容,则 {n} 仅包含整数,{quantity} 的其余部分(例如“PCS.”)从 {n} 和结果文本中剥离字符串。

在文本部分,可能会出现更多的整数。除找到的 {quantity} 之外的任何其他内容都应被视为文本的一部分,而不是解释为另一个数量。

我是一名前 C/C++ 程序员。如果我必须用这些语言解决这个问题,我可能会使用 lex 和 yacc 中的规则,否则我将不得不编写大量讨厌的代码来手动解析它。

我想学习一种在 Python 中高效编码的简洁方法,可能使用某种形式的规则来轻松支持更多情况。我想我可以在 Python 中使用 lex 和 yacc,但我想知道是否有更简单的方法。我是 Python 新手;我什至不知道从哪里开始。

我并不是要任何人为完整的解决方案编写代码,相反,我需要一两种方法,也许还有一些示例代码来展示如何做到这一点。

最佳答案

Pyparsing 可让您通过使用“+”和“|”将较小的解析器拼接在一起来构建解析器运营商(以及其他)。您还可以将名称附加到解析器中的各个元素,以便之后更容易获得值。

from pyparsing import (pyparsing_common, CaselessKeyword, Optional, ungroup, restOfLine, 
    oneOf, SkipTo)

int_qty = pyparsing_common.integer

# compose an expression for the quantity, in its various forms
"""
{n}
{n}PCS
{n}PC
{n}PCS.
{n}PC.
Lot of {n}
"""
LOT = CaselessKeyword("lot")
OF = CaselessKeyword("of")
pieces = oneOf("PC PCS PC. PCS.", caseless=True)
qty_expr = Optional(LOT + OF).suppress() + int_qty("qty") + Optional(pieces).suppress()

# compose expression for entire line
line_expr = SkipTo(qty_expr)("text1") + qty_expr + restOfLine("text2")

tests = """
    Send me 1000 widgets pronto!
    Deliver a Lot of 50 barrels of maple syrup by Monday, June 10.
    My shipment was short by 25 pcs.
    """

line_expr.runTests(tests)

打印:

Send me 1000 widgets pronto!
['Send me', 1000, ' widgets pronto!']
- qty: 1000
- text1: ['Send me']
- text2:  widgets pronto!


Deliver a Lot of 50 barrels of maple syrup by Monday, June 10.
['Deliver a ', 50, ' barrels of maple syrup by Monday, June 10.']
- qty: 50
- text1: ['Deliver a ']
- text2:  barrels of maple syrup by Monday, June 10.


My shipment was short by 25 pcs.
['My shipment was short by', 25, '']
- qty: 25
- text1: ['My shipment was short by']
- text2: 

编辑: Pyparsing 支持两种形式的匹配备选方案:MatchFirst,它在第一个匹配备选方案(使用“|”运算符定义)处停止,以及 Or,它评估所有备选方案并选择最长匹配(使用“^”运算符定义) .因此,如果您需要数量表达式的优先级,则可以显式定义它:

qty_pcs_expr = int_qty("qty") + White().suppress() + pieces.suppress()
qty_expr = Optional(LOT + OF).suppress() + int_qty("qty") + FollowedBy(White())

# compose expression for entire line
line_expr = (SkipTo(qty_pcs_expr)("text1") + qty_pcs_expr + restOfLine("text2") |
             SkipTo(qty_expr)("text1") + qty_expr + restOfLine("text2"))

这是新的测试:

tests = """
    Send me 1000 widgets pronto!
    Deliver a Lot of 50 barrels of maple syrup by Monday, June 10.
    My shipment was short by 25 pcs.
    2. I expect 22 pcs delivered in the morning
    On May 15 please deliver 1000 PCS.
    """

给予:

2. I expect 22 pcs delivered in the morning
['2. I expect ', 22, ' delivered in the morning']
- qty: 22
- text1: ['2. I expect ']
- text2:  delivered in the morning


On May 15 please deliver 1000 PCS.
['On May 15 please deliver ', 1000, '']
- qty: 1000
- text1: ['On May 15 please deliver ']
- text2: 

关于python - Python中字符串的复杂解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37844430/

相关文章:

python - 根据两列的值删除数据框 pandas 中的重复项

python - 我怎样才能改进这个 Pandas DataFrame 的结构?

python - 在每个循环中酸洗和加载 pandas 数据框以保存进度……坏主意?

python - 查找共享值的行

ios - 将 JSON 元素放入数组中

java - 对带有字符串前缀的数组进行二分搜索

c++ - 为什么声明为指向字符的指针并分配了 2 个字节大小的 String 的大小会被更改?

java - 子字符串范围 (Java)

java - 用于解析该字符串的正则表达式或java解决方案

ASP.net 代码中包含不执行