用于阅读文本的算法或模式

时间:2009-08-07 15:40:16

标签: algorithm parsing

我公司有一个客户跟踪不同地点不同公司的产品价格。这些信息会进入数据库。

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

有些看起来像这样:

    This is example text that could be many lines long...

    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

其他人看起来像这样:

    PRODUCT       PRICE    + / -
    ------------  -------- -------
    Location 1
    1             2007.30 +048.20
    2             2022.50 +048.20

    Maybe some multiline text here about a holiday or something...

    Location 2
    1             2017.30 +048.20
    2             2032.50 +048.20

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

对于我们来说,查看电子邮件并确定哪个价格与哪个产品位于哪个位置是微不足道的。但对我们的代码而言并非如此。因此,我正在尝试寻找更灵活的解决方案,并希望您就采取何种方法提出建议。我对从正则表达式到神经网络的任何事情持开放态度 - 我将学习如何使这项工作成功,我只是不知道我需要学习什么。这是一个lex / parsing问题吗?更类似于OCR?

代码不必单独找出所有格式。电子邮件分为几个主要的'样式',如上所述。我们确实需要代码足够灵活,以至于新产品系列或空格或某些内容不会使文件无法解析。

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

3 个答案:

答案 0 :(得分:7)

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

对于这些类型的任务,我会选择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']

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

我不知道是否有其他语言的等价物。

答案 1 :(得分:0)

您已为文本文件提供了两个模式样本 我认为这些可以用脚本来处理 类似于:AWK,sed,grep和bash脚本。


第一个样本中的一个模式,

  1. 部分以关键字Location [Number]开头
    • 第二行包含描述产品名称的列
    • 第三行部分包含产品价格的列
  2. 每个部分可以有不同数量的产品 每个文件可以有不同数量的部分 产品和价格始终在一个部分的指定行 空格分隔标识(product,price)列关联 部分中的产品数量与该部分中的价格数量相匹配。


    收集的数据可能会在数据库中被同化。

答案 2 :(得分:0)

我知道我会在这里使用的一件事是正则表达式。三个或四个表达式可以驱动每种电子邮件格式的解析逻辑。

我认为,尝试更频繁地编写解析引擎,可能会超出编程的范围。