1

我有一个如下字符串:

date                Not Important                         value    NotImportant2
11.11.13            useless . useless,21 useless 2        14.21    asmdakldm
21.12.12            fmpaosmfpoamsp 4                      41       ajfa9si90

我必须只提取最后的日期和值。

如果我使用标准过程来匹配多个单词,pyparsing 会将“不重要”列的最后一个数字匹配为“值”。

    anything = pp.Forward()
    anything << anyword + (value | anything)
    myParser = date + anything

我认为最好的方法是强制 pyparsing 匹配至少 2 个空格,但我真的不知道如何。有什么建议吗?

4

2 回答 2

2

描述

要匹配 2 个或更多空格,您可以使用\s{2,}

该表达式将:

  • 捕获日期字段
  • 捕获倒数第二个字段

^(\d{2}\.\d{2}\.\d{2})[^\r\n]*\s(\S+)\s{2,}\S+\s*(?:[\r\n]|\Z)

在此处输入图像描述

例子

现场演示

示例文本

date                Not Important                         value    NotImportant2
11.11.13            useless . useless,21 useless 2        14.21    asmdakldm
21.12.12            fmpaosmfpoamsp 4                      41       ajfa9si90

火柴

[0][0] = 11.11.13            useless . useless,21 useless 2        14.21    asmdakldm

[0][3] = 11.11.13
[0][4] = 14.21

[1][0] = 21.12.12            fmpaosmfpoamsp 4                      41       ajfa9si90
[1][5] = 21.12.12
[1][6] = 41
于 2013-07-29T12:15:03.820 回答
1

这个示例文本是柱状的,所以 pyparsing 在这里有点过分了。你可以写:

fieldslices = [slice(0,8), # dateslice
               slice(58,58+8), # valueslice
              ]

for line in sample:
    date,value = (line[x] for x in fieldslices)
    print date,value.strip()

并得到:

date     value
11.11.13 14.21
21.12.12 41

但是由于您特别想要一个 pyparsing 解决方案,那么对于如此多的东西,您可以使用GoToColumn该类:

from pyparsing import *

dateExpr = Regex(r'(\d\d\.){2}\d\d').setName("date")
realNum = Regex(r'\d+\.\d*').setName("real").setParseAction(lambda t:float(t[0]))
intNum = Regex(r'\d+').setName("integer").setParseAction(lambda t:int(t[0]))
valueExpr = realNum | intNum

patt = dateExpr("date") + GoToColumn(59) + valueExpr("value")

GoToColumn类似于SkipTo,但不是前进到表达式的下一个实例,而是前进到特定的列号(其中列号是从 1 开始,而不是像字符串切片中那样从 0 开始)。

现在这是应用于您的示例文本的解析器:

# Normally, input would be from some text file
# infile = open(sourcefile)
# but for this example, create iterator from the sample 
# text instead
sample = """\
date                Not Important                         value    NotImportant2
11.11.13            useless . useless,21 useless 2        14.21    asmdakldm
21.12.12            fmpaosmfpoamsp 4                      41       ajfa9si90
""".splitlines()

infile = iter(sample)

# skip header line
next(infile) 

for line in infile:
    result = patt.parseString(line)
    print result.dump()
    print

印刷:

['11.11.13', 'useless . useless,21 useless 2        ', 14.210000000000001]
- date: 11.11.13
- value: 14.21

['21.12.12', 'fmpaosmfpoamsp 4                      ', 41]
- date: 21.12.12
- value: 41

请注意,这些值已经从字符串转换为 int 或 float 类型;您可以为自己编写一个解析操作,将您的dd.mm.yy日期转换为 Python 日期时间。还要注意相关结果名称是如何定义的;这些允许您按名称访问各个字段,例如print result.date.

我还注意到您假设要获得一个或多个元素的序列,您使用了以下构造:

anything = pp.Forward()
anything << anyword + (value | anything)

虽然这确实有效,但它会创建一个运行时开销很大的递归表达式。pyparsing 提供了一个迭代等效项OneOrMore

anything = OneOrMore(anyword)

或者,如果您更喜欢较新的 '*' 运算符形式:

anything = anyword*(1,)

请浏览 pyparsing API 文档,这些文档包含在 pyparsing 的源代码分发中,或者在线访问http://packages.python.org/pyparsing/

欢迎来到 Pyparsing!

于 2013-07-30T07:25:04.553 回答