我公司有一个客户,它跟踪来自不同位置的不同公司的产品价格。该信息进入数据库。

这些公司每天通过电子邮件将价格发送给我们的客户,当然,电子邮件的格式也有所不同。不可能有任何一家公司更改其格式-他们不会这样做。

一些看起来像这样:

这是示例文本,可能长达多行...

位置1
产品1产品2产品3
$ 20.99 $ 21.99 $ 33.79

位置2
产品1产品2产品3
$ 24.99 $ 22.88 $ 35.59

其他人看起来像这样:

产品价格+/-
------------ -------- -------
位置1
1 2007.30 +048.20
2 2022.50 +048.20

也许这里有一些关于假期的多行文字...

位置2
1 2017.30 +048.20
2 2032.50 +048.20

目前,我们为每个公司的电子邮件格式编写了单独的解析器。但是这些格式经常会稍微改变。我们不能指望每次都在同一行或同一列上的价格。

对于我们来说,查看电子邮件并确定哪个价格与哪个产品在哪个位置的价格无关紧要。但是对于我们的代码而言,并没有那么多。因此,我正在尝试找到一种更灵活的解决方案,并希望您提出有关采用哪种方法的建议。我对从正则表达式到神经网络的任何事物都开放-我将学习完成这项工作所需的知识,我只是不知道需要学习什么。这是一个词法/解析问题吗?与OCR更相似?

该代码不必自己找出所有格式。电子邮件分为上述几种主要的“样式”。我们确实需要代码足够灵活,以至于新产品线或空格或其他东西不会使文件不可解析。

感谢您提供有关从何开始的建议。

最佳答案

我认为这个问题将适合于适当的解析器生成器。如果正则表达式出错,则很难对其进行测试和调试。但是,我会选择一个易于使用的解析器生成器,就像它是语言的一部分一样。

对于这些类型的任务,我将使用pyparsing,因为它具有完整的lr解析器的功能,但语法定义困难且辅助函数非常好。该代码也很容易阅读。

from pyparsing import *

aaa ="""    This is example text that could be many lines long...
             another line

    Location 1
    Product 1     Product 2     Product 3
    $20.99        $21.99        $33.79

    stuff in here you want to ignore

    Location 2
    Product 1     Product 2     Product 3
    $24.99        $22.88        $35.59 """

result = SkipTo("Location").suppress() \
# in place of "location" could be any type of match like a re.
         + OneOrMore(Word(alphas) + Word(nums)) \
         + OneOrMore(Word(nums+"$.")) \

all_results = OneOrMore(Group(result))

parsed = all_results.parseString(aaa)

for block in parsed:
    print block

这将返回列表列表。
['Location', '1', 'Product', '1', 'Product', '2', 'Product', '3', '$20.99', '$21.99', '$33.79']
['Location', '2', 'Product', '1', 'Product', '2', 'Product', '3', '$24.99', '$22.88', '$35.59']

您可以根据需要对事物进行分组,但为简单起见,我只返回了列表。默认情况下,空格被忽略,这使事情变得更加简单。

我不知道其他语言是否等效。

10-04 14:15